diff options
59 files changed, 499 insertions, 387 deletions
| diff --git a/data/op-mode-standardized.json b/data/op-mode-standardized.json index 2ea4d945a..7c5524675 100644 --- a/data/op-mode-standardized.json +++ b/data/op-mode-standardized.json @@ -8,6 +8,7 @@  "dhcp.py",  "dns.py",  "interfaces.py", +"lldp.py",  "log.py",  "memory.py",  "nat.py", diff --git a/data/templates/chrony/chrony.conf.j2 b/data/templates/chrony/chrony.conf.j2 new file mode 100644 index 000000000..b3bfc8c0c --- /dev/null +++ b/data/templates/chrony/chrony.conf.j2 @@ -0,0 +1,58 @@ +### Autogenerated by ntp.py ### + +# This would step the system clock if the adjustment is larger than 0.1 seconds, +# but only in the first three clock updates. +makestep 1.0 3 + +# The rtcsync directive enables a mode where the system time is periodically +# copied to the RTC and chronyd does not try to track its drift. This directive +# cannot be used with the rtcfile directive. On Linux, the RTC copy is performed +# by the kernel every 11 minutes. +rtcsync + +# This directive specifies the maximum amount of memory that chronyd is allowed +# to allocate for logging of client accesses and the state that chronyd as an +# NTP server needs to support the interleaved mode for its clients. +clientloglimit 1048576 + +driftfile /run/chrony/drift +dumpdir /run/chrony +pidfile {{ config_file | replace('.conf', '.pid') }} + +# Determine when will the next leap second occur and what is the current offset +leapsectz right/UTC + +user {{ user }} + +# NTP servers to reach out to +{% if server is vyos_defined %} +{%     for server, config in server.items() %} +{%         set association = 'server' %} +{%         if config.pool is vyos_defined %} +{%             set association = 'pool' %} +{%         endif %} +{{ association }} {{ server | replace('_', '-') }} iburst {{ 'noselect' if config.noselect is vyos_defined }} {{ 'prefer' if config.prefer is vyos_defined }} +{%     endfor %} +{% endif %} + +# Allowed clients configuration +{% if allow_client.address is vyos_defined %} +{%     for address in allow_client.address %} +allow {{ address }} +{%     endfor %} +{% endif %} +deny all + +{% if listen_address is vyos_defined or interface is vyos_defined %} +# NTP should listen on configured addresses only +{%     if listen_address is vyos_defined %} +{%         for address in listen_address %} +bindaddress {{ address }} +{%         endfor %} +{%     endif %} +{%     if interface is vyos_defined %} +{%         for ifname in interface %} +binddevice {{ ifname }} +{%         endfor %} +{%     endif %} +{% endif %} diff --git a/data/templates/ntp/override.conf.j2 b/data/templates/chrony/override.conf.j2 index 6fed9d7d2..9eaea7608 100644 --- a/data/templates/ntp/override.conf.j2 +++ b/data/templates/chrony/override.conf.j2 @@ -5,10 +5,13 @@ ConditionPathExists={{ config_file }}  After=vyos-router.service  [Service] +EnvironmentFile=  ExecStart= -ExecStart={{ vrf_command }}/usr/sbin/ntpd -g -p {{ config_file | replace('.conf', '.pid') }} -c {{ config_file }} -u ntp:ntp +ExecStart={{ vrf_command }}/usr/sbin/chronyd -F 1 -f {{ config_file }}  PIDFile=  PIDFile={{ config_file | replace('.conf', '.pid') }}  Restart=always  RestartSec=10 +# Required for VRF support +ProtectControlGroups=No diff --git a/data/templates/frr/ospfd.frr.j2 b/data/templates/frr/ospfd.frr.j2 index 0baff2d72..8c4a81c57 100644 --- a/data/templates/frr/ospfd.frr.j2 +++ b/data/templates/frr/ospfd.frr.j2 @@ -84,11 +84,13 @@ router ospf {{ 'vrf ' ~ vrf if vrf is vyos_defined }}  {%         endfor %}  {%         if area_config.range is vyos_defined %}  {%             for range, range_config in area_config.range.items() %} -{%                 if range_config.cost is vyos_defined %} - area {{ area_id }} range {{ range }} cost {{ range_config.cost }} -{%                 endif %}  {%                 if range_config.not_advertise is vyos_defined %}   area {{ area_id }} range {{ range }} not-advertise +{%                 else %} + area {{ area_id }} range {{ range }} +{%                 endif %} +{%                 if range_config.cost is vyos_defined %} + area {{ area_id }} range {{ range }} cost {{ range_config.cost }}  {%                 endif %}  {%                 if range_config.substitute is vyos_defined %}   area {{ area_id }} range {{ range }} substitute {{ range_config.substitute }} diff --git a/data/templates/ipsec/swanctl/peer.j2 b/data/templates/ipsec/swanctl/peer.j2 index 837fa263c..9d95271fe 100644 --- a/data/templates/ipsec/swanctl/peer.j2 +++ b/data/templates/ipsec/swanctl/peer.j2 @@ -45,11 +45,7 @@  {% endif %}          }          remote { -{% if peer_conf.authentication.remote_id is vyos_defined %}              id = "{{ peer_conf.authentication.remote_id }}" -{% else %} -            id = "{{ peer }}" -{% endif %}              auth = {{ 'psk' if peer_conf.authentication.mode == 'pre-shared-secret' else 'pubkey' }}  {% if peer_conf.authentication.mode == 'rsa' %}              pubkeys = {{ peer_conf.authentication.rsa.remote_key }}.pem diff --git a/data/templates/ntp/ntpd.conf.j2 b/data/templates/ntp/ntpd.conf.j2 deleted file mode 100644 index 8921826fa..000000000 --- a/data/templates/ntp/ntpd.conf.j2 +++ /dev/null @@ -1,49 +0,0 @@ -### Autogenerated by ntp.py ### - -# -# Non-configurable defaults -# -driftfile /var/lib/ntp/ntp.drift -# By default, only allow ntpd to query time sources, ignore any incoming requests -restrict default noquery nopeer notrap nomodify -# Allow pool associations -restrict source nomodify notrap noquery -# Local users have unrestricted access, allowing reconfiguration via ntpdc -restrict 127.0.0.1 -restrict -6 ::1 - -# -# Configurable section -# -{% if server is vyos_defined %} -{%     for server, config in server.items() %} -{%         set association = 'server' %} -{%         if config.pool is vyos_defined %} -{%             set association = 'pool' %} -{%         endif %} -{{ association }} {{ server | replace('_', '-') }} iburst {{ 'noselect' if config.noselect is vyos_defined }} {{ 'preempt' if config.preempt is vyos_defined }} {{ 'prefer' if config.prefer is vyos_defined }} -{%     endfor %} -{% endif %} - -{% if allow_clients.address is vyos_defined %} -# Allowed clients configuration -restrict default ignore -{%     for address in allow_clients.address %} -restrict {{ address | address_from_cidr }} mask {{ address | netmask_from_cidr }} nomodify notrap nopeer -{%     endfor %} -{% endif %} - -{% if listen_address is vyos_defined or interface is vyos_defined %} -# NTP should listen on configured addresses only -interface ignore wildcard -{%     if listen_address is vyos_defined %} -{%         for address in listen_address %} -interface listen {{ address }} -{%         endfor %} -{%     endif %} -{%     if interface is vyos_defined %} -{%         for ifname in interface %} -interface listen {{ ifname }} -{%         endfor %} -{%     endif %} -{% endif %} diff --git a/data/templates/telegraf/telegraf.j2 b/data/templates/telegraf/telegraf.j2 index 36571ce98..c9f402281 100644 --- a/data/templates/telegraf/telegraf.j2 +++ b/data/templates/telegraf/telegraf.j2 @@ -102,7 +102,7 @@    dirs = ["/proc/sys/net/ipv4/netfilter","/proc/sys/net/netfilter"]  [[inputs.ethtool]]    interface_include = {{ interfaces_ethernet }} -[[inputs.ntpq]] +[[inputs.chrony]]    dns_lookup = true  [[inputs.internal]]  [[inputs.nstat]] diff --git a/debian/control b/debian/control index a477bffec..1e593d378 100644 --- a/debian/control +++ b/debian/control @@ -101,8 +101,7 @@ Depends:    nfct,    nftables (>= 0.9.3),    nginx-light, -  ntp, -  ntpdate, +  chrony,    nvme-cli,    ocserv,    opennhrp, diff --git a/interface-definitions/include/version/ntp-version.xml.i b/interface-definitions/include/version/ntp-version.xml.i index cc4ff9a1c..9eafbf7f0 100644 --- a/interface-definitions/include/version/ntp-version.xml.i +++ b/interface-definitions/include/version/ntp-version.xml.i @@ -1,3 +1,3 @@  <!-- include start from include/version/ntp-version.xml.i --> -<syntaxVersion component='ntp' version='1'></syntaxVersion> +<syntaxVersion component='ntp' version='2'></syntaxVersion>  <!-- include end --> diff --git a/interface-definitions/ntp.xml.in b/interface-definitions/ntp.xml.in index 85636a50f..65e40ee32 100644 --- a/interface-definitions/ntp.xml.in +++ b/interface-definitions/ntp.xml.in @@ -1,7 +1,7 @@  <?xml version="1.0"?>  <!-- NTP configuration -->  <interfaceDefinition> -  <node name="system"> +  <node name="service">      <children>        <node name="ntp" owner="${vyos_conf_scripts_dir}/ntp.py">          <properties> @@ -43,12 +43,6 @@                    <valueless/>                  </properties>                </leafNode> -              <leafNode name="preempt"> -                <properties> -                  <help>Specifies the association as preemptable rather than the default persistent</help> -                  <valueless/> -                </properties> -              </leafNode>                <leafNode name="prefer">                  <properties>                    <help>Marks the server as preferred</help> @@ -57,24 +51,33 @@                </leafNode>              </children>            </tagNode> -          <node name="allow-clients"> +          <node name="allow-client">              <properties> -              <help>Network Time Protocol (NTP) server options</help> +              <help>Specify NTP clients allowed to access the server</help>              </properties>              <children>                <leafNode name="address">                  <properties>                    <help>IP address</help>                    <valueHelp> +                    <format>ipv4</format> +                    <description>Allowed IPv4 address</description> +                  </valueHelp> +                  <valueHelp>                      <format>ipv4net</format> -                    <description>IP address and prefix length</description> +                    <description>Allowed IPv4 prefix</description> +                  </valueHelp> +                  <valueHelp> +                    <format>ipv6</format> +                    <description>Allowed IPv6 address</description>                    </valueHelp>                    <valueHelp>                      <format>ipv6net</format> -                    <description>IPv6 address and prefix length</description> +                    <description>Allowed IPv6 prefix</description>                    </valueHelp>                    <multi/>                    <constraint> +                    <validator name="ip-address"/>                      <validator name="ip-prefix"/>                    </constraint>                  </properties> diff --git a/interface-definitions/vpn-ipsec.xml.in b/interface-definitions/vpn-ipsec.xml.in index 64966b540..fd74a51d7 100644 --- a/interface-definitions/vpn-ipsec.xml.in +++ b/interface-definitions/vpn-ipsec.xml.in @@ -957,6 +957,7 @@                              <description>ID used for peer authentication</description>                            </valueHelp>                          </properties> +                        <defaultValue>%any</defaultValue>                        </leafNode>                        <leafNode name="use-x509-id">                          <properties> diff --git a/op-mode-definitions/date.xml.in b/op-mode-definitions/date.xml.in index 15a69dbd9..6d8586025 100644 --- a/op-mode-definitions/date.xml.in +++ b/op-mode-definitions/date.xml.in @@ -37,28 +37,6 @@          </properties>          <command>/bin/date "$3"</command>        </tagNode> -      <node name="date"> -        <properties> -          <help>Set system date and time</help> -        </properties> -        <children> -          <node name="ntp"> -            <properties> -              <help>Set system date and time from NTP server (default: 0.pool.ntp.org)</help> -            </properties> -            <command>/usr/sbin/ntpdate -u 0.pool.ntp.org</command> -          </node> -          <tagNode name="ntp"> -            <properties> -              <help>Set system date and time from NTP server</help> -              <completionHelp> -                <script>${vyos_completion_dir}/list_ntp_servers.sh</script> -              </completionHelp> -            </properties> -            <command>/usr/sbin/ntpdate -u "$4"</command> -          </tagNode> -        </children> -      </node>      </children>    </node>  </interfaceDefinition> diff --git a/op-mode-definitions/lldp.xml.in b/op-mode-definitions/lldp.xml.in index 297ccf1f4..07cafa77f 100644 --- a/op-mode-definitions/lldp.xml.in +++ b/op-mode-definitions/lldp.xml.in @@ -11,14 +11,8 @@              <properties>                <help>Show LLDP neighbors</help>              </properties> -            <command>${vyos_op_scripts_dir}/lldp_op.py --all</command> +            <command>${vyos_op_scripts_dir}/lldp.py show_neighbors</command>              <children> -              <node name="detail"> -                <properties> -                  <help>Show LLDP neighbor details</help> -                </properties> -                <command>${vyos_op_scripts_dir}/lldp_op.py --detail</command> -              </node>                <tagNode name="interface">                  <properties>                    <help>Show LLDP for specified interface</help> @@ -26,7 +20,7 @@                      <script>${vyos_completion_dir}/list_interfaces.py</script>                    </completionHelp>                  </properties> -                <command>${vyos_op_scripts_dir}/lldp_op.py --interface $5</command> +                <command>${vyos_op_scripts_dir}/lldp.py show_neighbors --interface $5</command>                </tagNode>              </children>            </node> diff --git a/op-mode-definitions/monitor-log.xml.in b/op-mode-definitions/monitor-log.xml.in index 8abc5f4db..d616bfc08 100644 --- a/op-mode-definitions/monitor-log.xml.in +++ b/op-mode-definitions/monitor-log.xml.in @@ -101,9 +101,15 @@            </leafNode>            <leafNode name="nhrp">              <properties> -              <help>Monitor last lines of NHRP log</help> +              <help>Monitor last lines of Next Hop Resolution Protocol (NHRP) log</help>              </properties> -            <command>journalctl --no-hostname --boot --unit opennhrp.service</command> +            <command>journalctl --no-hostname --boot --follow --unit opennhrp.service</command> +          </leafNode> +          <leafNode name="ntp"> +            <properties> +              <help>Monitor last lines of Network Time Protocol (NTP) log</help> +            </properties> +            <command>journalctl --no-hostname --boot --follow --unit chrony.service</command>            </leafNode>            <node name="pppoe">              <properties> diff --git a/op-mode-definitions/show-interfaces-bonding.xml.in b/op-mode-definitions/show-interfaces-bonding.xml.in index 6908153dd..c41e7bd5f 100644 --- a/op-mode-definitions/show-interfaces-bonding.xml.in +++ b/op-mode-definitions/show-interfaces-bonding.xml.in @@ -11,13 +11,13 @@                  <path>interfaces bonding</path>                </completionHelp>              </properties> -            <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4"</command> +            <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4" --intf_type=bonding</command>              <children>                <leafNode name="brief">                  <properties>                    <help>Show summary of the specified bonding interface information</help>                  </properties> -                <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_name="$4"</command> +                <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_name="$4" --intf_type=bonding</command>                </leafNode>                <leafNode name="detail">                  <properties> @@ -38,13 +38,13 @@                      <path>interfaces bonding ${COMP_WORDS[3]} vif</path>                    </completionHelp>                  </properties> -                <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4.$6"</command> +                <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4.$6" --intf_type=bonding</command>                  <children>                    <leafNode name="brief">                      <properties>                        <help>Show summary of specified virtual network interface (vif) information</help>                      </properties> -                    <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_name="$4.$6"</command> +                    <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_name="$4.$6" --intf_type=bonding</command>                    </leafNode>                  </children>                </tagNode> diff --git a/op-mode-definitions/show-interfaces-bridge.xml.in b/op-mode-definitions/show-interfaces-bridge.xml.in index b950c3a17..22cd3ee67 100644 --- a/op-mode-definitions/show-interfaces-bridge.xml.in +++ b/op-mode-definitions/show-interfaces-bridge.xml.in @@ -11,13 +11,13 @@                  <path>interfaces bridge</path>                </completionHelp>              </properties> -            <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4"</command> +            <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4" --intf_type=bridge</command>              <children>                <leafNode name="brief">                  <properties>                    <help>Show summary of the specified bridge interface information</help>                  </properties> -                <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_name="$4"</command> +                <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_name="$4" --intf_type=bridge</command>                </leafNode>              </children>            </tagNode> diff --git a/op-mode-definitions/show-interfaces-dummy.xml.in b/op-mode-definitions/show-interfaces-dummy.xml.in index 398e00636..958d3483d 100644 --- a/op-mode-definitions/show-interfaces-dummy.xml.in +++ b/op-mode-definitions/show-interfaces-dummy.xml.in @@ -11,13 +11,13 @@                  <path>interfaces dummy</path>                </completionHelp>              </properties> -            <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4"</command> +            <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4" --intf_type=dummy</command>              <children>                <leafNode name="brief">                  <properties>                    <help>Show summary of the specified dummy interface information</help>                  </properties> -                <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_name="$4"</command> +                <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_name="$4" --intf_type=dummy</command>                </leafNode>              </children>            </tagNode> diff --git a/op-mode-definitions/show-interfaces-ethernet.xml.in b/op-mode-definitions/show-interfaces-ethernet.xml.in index 40d4adbb2..81759c2b6 100644 --- a/op-mode-definitions/show-interfaces-ethernet.xml.in +++ b/op-mode-definitions/show-interfaces-ethernet.xml.in @@ -11,13 +11,13 @@                  <path>interfaces ethernet</path>                </completionHelp>              </properties> -            <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4"</command> +            <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4" --intf_type=ethernet</command>              <children>                <leafNode name="brief">                  <properties>                    <help>Show summary of the specified ethernet interface information</help>                  </properties> -                <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_name="$4"</command> +                <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_name="$4" --intf_type=ethernet</command>                </leafNode>                <leafNode name="identify">                  <properties> @@ -58,13 +58,13 @@                      <path>interfaces ethernet ${COMP_WORDS[3]} vif</path>                    </completionHelp>                  </properties> -                <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4.$6"</command> +                <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4.$6" --intf_type=ethernet</command>                  <children>                    <leafNode name="brief">                      <properties>                        <help>Show summary of specified virtual network interface (vif) information</help>                      </properties> -                    <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_name="$4.$6"</command> +                    <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_name="$4.$6" --intf_type=ethernet</command>                    </leafNode>                  </children>                </tagNode> diff --git a/op-mode-definitions/show-interfaces-geneve.xml.in b/op-mode-definitions/show-interfaces-geneve.xml.in index be3084af3..3cf45878d 100644 --- a/op-mode-definitions/show-interfaces-geneve.xml.in +++ b/op-mode-definitions/show-interfaces-geneve.xml.in @@ -11,13 +11,13 @@                  <path>interfaces geneve</path>                </completionHelp>              </properties> -            <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4"</command> +            <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4" --intf_type=geneve</command>              <children>                <leafNode name="brief">                  <properties>                    <help>Show summary of the specified GENEVE interface information</help>                  </properties> -                <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_name="$4"</command> +                <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_name="$4" --intf_type=geneve</command>                </leafNode>              </children>            </tagNode> diff --git a/op-mode-definitions/show-interfaces-input.xml.in b/op-mode-definitions/show-interfaces-input.xml.in index 1f8505160..5d93dcee6 100644 --- a/op-mode-definitions/show-interfaces-input.xml.in +++ b/op-mode-definitions/show-interfaces-input.xml.in @@ -11,13 +11,13 @@                  <path>interfaces input</path>                </completionHelp>              </properties> -            <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4"</command> +            <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4" --intf_type=input</command>              <children>                <leafNode name="brief">                  <properties>                    <help>Show summary of the specified input interface information</help>                  </properties> -                <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_name="$4"</command> +                <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_name="$4" --intf_type=input</command>                </leafNode>              </children>            </tagNode> diff --git a/op-mode-definitions/show-interfaces-l2tpv3.xml.in b/op-mode-definitions/show-interfaces-l2tpv3.xml.in index ff08b8266..713e36dac 100644 --- a/op-mode-definitions/show-interfaces-l2tpv3.xml.in +++ b/op-mode-definitions/show-interfaces-l2tpv3.xml.in @@ -11,13 +11,13 @@                  <path>interfaces l2tpv3</path>                </completionHelp>              </properties> -            <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4"</command> +            <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4" --intf_type=l2tpv3</command>              <children>                <leafNode name="brief">                  <properties>                    <help>Show summary of the specified L2TPv3 interface information</help>                  </properties> -                <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_name="$4"</command> +                <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_name="$4" --intf_type=l2tpv3</command>                </leafNode>              </children>            </tagNode> diff --git a/op-mode-definitions/show-interfaces-loopback.xml.in b/op-mode-definitions/show-interfaces-loopback.xml.in index 9919bf32b..a24151cc3 100644 --- a/op-mode-definitions/show-interfaces-loopback.xml.in +++ b/op-mode-definitions/show-interfaces-loopback.xml.in @@ -11,13 +11,13 @@                  <path>interfaces loopback</path>                </completionHelp>              </properties> -            <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4"</command> +            <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4" --intf_type=loopback</command>              <children>                <leafNode name="brief">                  <properties>                    <help>Show summary of the specified Loopback interface information</help>                  </properties> -                <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_name="$4"</command> +                <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_name="$4" --intf_type=loopback</command>                </leafNode>              </children>            </tagNode> diff --git a/op-mode-definitions/show-interfaces-pppoe.xml.in b/op-mode-definitions/show-interfaces-pppoe.xml.in index 80bfd00ff..a34473148 100644 --- a/op-mode-definitions/show-interfaces-pppoe.xml.in +++ b/op-mode-definitions/show-interfaces-pppoe.xml.in @@ -11,7 +11,7 @@                  <path>interfaces pppoe</path>                </completionHelp>              </properties> -            <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4"</command> +            <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4" --intf_type=pppoe</command>              <children>                <leafNode name="log">                  <properties> diff --git a/op-mode-definitions/show-interfaces-pseudo-ethernet.xml.in b/op-mode-definitions/show-interfaces-pseudo-ethernet.xml.in index 0c00dbdd0..cb62639ee 100644 --- a/op-mode-definitions/show-interfaces-pseudo-ethernet.xml.in +++ b/op-mode-definitions/show-interfaces-pseudo-ethernet.xml.in @@ -11,13 +11,13 @@                  <path>interfaces pseudo-ethernet</path>                </completionHelp>              </properties> -            <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4"</command> +            <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4" --intf_type=pseudo-ethernet</command>              <children>                <leafNode name="brief">                  <properties>                    <help>Show summary of the specified pseudo-ethernet/MACvlan interface information</help>                  </properties> -                <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_name="$4"</command> +                <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_name="$4" --intf_type=pseudo-ethernet</command>                </leafNode>              </children>            </tagNode> diff --git a/op-mode-definitions/show-interfaces-sstpc.xml.in b/op-mode-definitions/show-interfaces-sstpc.xml.in index c473f9822..a619a9fd2 100644 --- a/op-mode-definitions/show-interfaces-sstpc.xml.in +++ b/op-mode-definitions/show-interfaces-sstpc.xml.in @@ -11,7 +11,7 @@                  <path>interfaces sstpc</path>                </completionHelp>              </properties> -            <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4"</command> +            <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4" --intf_type=sstpc</command>              <children>                <leafNode name="log">                  <properties> diff --git a/op-mode-definitions/show-interfaces-tunnel.xml.in b/op-mode-definitions/show-interfaces-tunnel.xml.in index 4af90b813..10e10e655 100644 --- a/op-mode-definitions/show-interfaces-tunnel.xml.in +++ b/op-mode-definitions/show-interfaces-tunnel.xml.in @@ -11,13 +11,13 @@                  <path>interfaces tunnel</path>                </completionHelp>              </properties> -            <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4"</command> +            <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4" --intf_type=tunnel</command>              <children>                <leafNode name="brief">                  <properties>                    <help>Show summary of the specified tunnel interface information</help>                  </properties> -                <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_name="$4"</command> +                <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_name="$4" --intf_type=tunnel</command>                </leafNode>              </children>            </tagNode> diff --git a/op-mode-definitions/show-interfaces-virtual-ethernet.xml.in b/op-mode-definitions/show-interfaces-virtual-ethernet.xml.in index 2aa71c687..c743492fb 100644 --- a/op-mode-definitions/show-interfaces-virtual-ethernet.xml.in +++ b/op-mode-definitions/show-interfaces-virtual-ethernet.xml.in @@ -11,13 +11,13 @@                  <path>interfaces virtual-ethernet</path>                </completionHelp>              </properties> -            <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4"</command> +            <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4" --intf_type=virtual-ethernet</command>              <children>                <leafNode name="brief">                  <properties>                    <help>Show summary of the specified virtual-ethernet interface information</help>                  </properties> -                <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_name="$4"</command> +                <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_name="$4" --intf_type=virtual-ethernet</command>                </leafNode>              </children>            </tagNode> diff --git a/op-mode-definitions/show-interfaces-vti.xml.in b/op-mode-definitions/show-interfaces-vti.xml.in index 195e1d5da..d532894b7 100644 --- a/op-mode-definitions/show-interfaces-vti.xml.in +++ b/op-mode-definitions/show-interfaces-vti.xml.in @@ -11,13 +11,13 @@                  <path>interfaces vti</path>                </completionHelp>              </properties> -            <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4"</command> +            <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4" --intf_type=vti</command>              <children>                <leafNode name="brief">                  <properties>                    <help>Show summary of the specified vti interface information</help>                  </properties> -                <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_name="$4"</command> +                <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_name="$4" --intf_type=vti</command>                </leafNode>              </children>            </tagNode> diff --git a/op-mode-definitions/show-interfaces-vxlan.xml.in b/op-mode-definitions/show-interfaces-vxlan.xml.in index a1d01a6af..fde832551 100644 --- a/op-mode-definitions/show-interfaces-vxlan.xml.in +++ b/op-mode-definitions/show-interfaces-vxlan.xml.in @@ -11,13 +11,13 @@                  <path>interfaces vxlan</path>                </completionHelp>              </properties> -            <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4"</command> +            <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4" --intf_type=vxlan</command>              <children>                <leafNode name="brief">                  <properties>                    <help>Show summary of the specified VXLAN interface information</help>                  </properties> -                <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_name="$4"</command> +                <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_name="$4" --intf_type=vxlan</command>                </leafNode>              </children>            </tagNode> diff --git a/op-mode-definitions/show-interfaces-wireguard.xml.in b/op-mode-definitions/show-interfaces-wireguard.xml.in index 55879cfff..eba8de568 100644 --- a/op-mode-definitions/show-interfaces-wireguard.xml.in +++ b/op-mode-definitions/show-interfaces-wireguard.xml.in @@ -11,7 +11,7 @@                  <script>${vyos_completion_dir}/list_interfaces.py --type wireguard</script>                </completionHelp>              </properties> -	        <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4"</command> +	        <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4" --intf_type=wireguard</command>              <children>                <leafNode name="allowed-ips">                  <properties> diff --git a/op-mode-definitions/show-interfaces-wireless.xml.in b/op-mode-definitions/show-interfaces-wireless.xml.in index 7ae2c8ce4..b0a272225 100644 --- a/op-mode-definitions/show-interfaces-wireless.xml.in +++ b/op-mode-definitions/show-interfaces-wireless.xml.in @@ -31,13 +31,13 @@                  <script>${vyos_completion_dir}/list_interfaces.py --type wireless</script>                </completionHelp>              </properties> -            <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4"</command> +            <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4" --intf_type=wireless</command>              <children>                <leafNode name="brief">                  <properties>                    <help>Show summary of the specified wireless interface information</help>                  </properties> -                <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_name="$4"</command> +                <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_name="$4" --intf_type=wireless</command>                </leafNode>                <node name="scan">                  <properties> @@ -63,13 +63,13 @@                  <properties>                    <help>Show specified virtual network interface (vif) information</help>                  </properties> -                <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4.$6"</command> +                <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4.$6" --intf_type=wireless</command>                  <children>                    <leafNode name="brief">                      <properties>                        <help>Show summary of specified virtual network interface (vif) information</help>                      </properties> -                    <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_name="$4.$6"</command> +                    <command>${vyos_op_scripts_dir}/interfaces.py show_summary --intf_name="$4.$6" --intf_type=wireless</command>                    </leafNode>                  </children>                </tagNode> diff --git a/op-mode-definitions/show-interfaces-wwan.xml.in b/op-mode-definitions/show-interfaces-wwan.xml.in index 8ac5933a2..17d4111a9 100644 --- a/op-mode-definitions/show-interfaces-wwan.xml.in +++ b/op-mode-definitions/show-interfaces-wwan.xml.in @@ -12,7 +12,7 @@                  <script>cd /sys/class/net; ls -d wwan*</script>                </completionHelp>              </properties> -            <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4"</command> +            <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4" --intf_type=wirelessmodem</command>              <children>                <leafNode name="capabilities">                  <properties> diff --git a/op-mode-definitions/show-log.xml.in b/op-mode-definitions/show-log.xml.in index 977ece453..6608ea0d8 100644 --- a/op-mode-definitions/show-log.xml.in +++ b/op-mode-definitions/show-log.xml.in @@ -204,7 +204,7 @@            </leafNode>            <leafNode name="lldp">              <properties> -              <help>Show log for LLDP</help> +              <help>Show log for Link Layer Discovery Protocol (LLDP)</help>              </properties>              <command>journalctl --no-hostname --boot --unit lldpd.service</command>            </leafNode> @@ -216,10 +216,16 @@            </leafNode>            <leafNode name="nhrp">              <properties> -              <help>Show log for NHRP</help> +              <help>Show log for Next Hop Resolution Protocol (NHRP)</help>              </properties>              <command>journalctl --no-hostname --boot --unit opennhrp.service</command>            </leafNode> +          <leafNode name="ntp"> +            <properties> +              <help>Show log for Network Time Protocol (NTP)</help> +            </properties> +            <command>journalctl --no-hostname --boot --unit chrony.service</command> +          </leafNode>            <node name="macsec">              <properties>                <help>Show log for MACsec</help> diff --git a/op-mode-definitions/show-ntp.xml.in b/op-mode-definitions/show-ntp.xml.in index 01f4477d8..0907722af 100644 --- a/op-mode-definitions/show-ntp.xml.in +++ b/op-mode-definitions/show-ntp.xml.in @@ -6,22 +6,13 @@          <properties>            <help>Show peer status of NTP daemon</help>          </properties> -        <command>${vyos_op_scripts_dir}/show_ntp.sh --basic</command> +        <command>${vyos_op_scripts_dir}/show_ntp.sh --sourcestats</command>          <children> -          <tagNode name="server"> +          <node name="system">              <properties> -              <help>Show date and time of specified NTP server</help> -              <completionHelp> -                <script>${vyos_completion_dir}/list_ntp_servers.sh</script> -              </completionHelp> +              <help>Show parameters about the system clock performance</help>              </properties> -            <command>${vyos_op_scripts_dir}/show_ntp.sh --server "$4"</command> -          </tagNode> -          <node name="info"> -            <properties> -              <help>Show NTP operational summary</help> -            </properties> -            <command>${vyos_op_scripts_dir}/show_ntp.sh --info</command> +            <command>${vyos_op_scripts_dir}/show_ntp.sh --tracking</command>            </node>          </children>        </node> diff --git a/python/vyos/configsession.py b/python/vyos/configsession.py index 9864aa5c5..df44fd8d6 100644 --- a/python/vyos/configsession.py +++ b/python/vyos/configsession.py @@ -34,8 +34,8 @@ REMOVE_IMAGE = ['/opt/vyatta/bin/vyatta-boot-image.pl', '--del']  GENERATE = ['/opt/vyatta/bin/vyatta-op-cmd-wrapper', 'generate']  SHOW = ['/opt/vyatta/bin/vyatta-op-cmd-wrapper', 'show']  RESET = ['/opt/vyatta/bin/vyatta-op-cmd-wrapper', 'reset'] -ADD = ['/opt/vyatta/bin/vyatta-op-cmd-wrapper', 'add'] -DELETE = ['/opt/vyatta/bin/vyatta-op-cmd-wrapper', 'delete'] +OP_CMD_ADD = ['/opt/vyatta/bin/vyatta-op-cmd-wrapper', 'add'] +OP_CMD_DELETE = ['/opt/vyatta/bin/vyatta-op-cmd-wrapper', 'delete']  # Default "commit via" string  APP = "vyos-http-api" @@ -208,11 +208,11 @@ class ConfigSession(object):          return out      def add_container_image(self, name): -        out = self.__run_command(ADD + ['container', 'image'] + [name]) +        out = self.__run_command(OP_CMD_ADD + ['container', 'image'] + [name])          return out      def delete_container_image(self, name): -        out = self.__run_command(DELETE + ['container', 'image'] + [name]) +        out = self.__run_command(OP_CMD_DELETE + ['container', 'image'] + [name])          return out      def show_container_image(self): diff --git a/python/vyos/ifconfig/ethernet.py b/python/vyos/ifconfig/ethernet.py index 519cfc58c..5080144ff 100644 --- a/python/vyos/ifconfig/ethernet.py +++ b/python/vyos/ifconfig/ethernet.py @@ -239,7 +239,7 @@ class EthernetIf(Interface):          if not isinstance(state, bool):              raise ValueError('Value out of range') -        rps_cpus = '0' +        rps_cpus = 0          queues = len(glob(f'/sys/class/net/{self.ifname}/queues/rx-*'))          if state:              # Enable RPS on all available CPUs except CPU0 which we will not @@ -248,10 +248,16 @@ class EthernetIf(Interface):              # representation of the CPUs which should participate on RPS, we              # can enable more CPUs that are physically present on the system,              # Linux will clip that internally! -            rps_cpus = 'ffffffff,ffffffff,ffffffff,fffffffe' +            rps_cpus = (1 << os.cpu_count()) -1 + +            # XXX: we should probably reserve one core when the system is under +            # high preasure so we can still have a core left for housekeeping. +            # This is done by masking out the lowst bit so CPU0 is spared from +            # receive packet steering. +            rps_cpus &= ~1          for i in range(0, queues): -            self._write_sysfs(f'/sys/class/net/{self.ifname}/queues/rx-{i}/rps_cpus', rps_cpus) +            self._write_sysfs(f'/sys/class/net/{self.ifname}/queues/rx-{i}/rps_cpus', f'{rps_cpus:x}')          # send bitmask representation as hex string without leading '0x'          return True diff --git a/python/vyos/opmode.py b/python/vyos/opmode.py index 19c476b1c..30e893d74 100644 --- a/python/vyos/opmode.py +++ b/python/vyos/opmode.py @@ -70,13 +70,13 @@ class InternalError(Error):  def _is_op_mode_function_name(name): -    if re.match(r"^(show|clear|reset|restart|add|delete)", name): +    if re.match(r"^(show|clear|reset|restart|add|delete|generate)", name):          return True      else:          return False -def _is_show(name): -    if re.match(r"^show", name): +def _capture_output(name): +    if re.match(r"^(show|generate)", name):          return True      else:          return False @@ -203,14 +203,14 @@ def run(module):      # it would cause an extra argument error when we pass the dict to a function      del args["subcommand"] -    # Show commands must always get the "raw" argument, -    # but other commands (clear/reset/restart) should not, +    # Show and generate commands must always get the "raw" argument, +    # but other commands (clear/reset/restart/add/delete) should not,      # because they produce no output and it makes no sense for them. -    if ("raw" not in args) and _is_show(function_name): +    if ("raw" not in args) and _capture_output(function_name):          args["raw"] = False -    if re.match(r"^show", function_name): -        # Show commands are slightly special: +    if _capture_output(function_name): +        # Show and generate commands are slightly special:          # they may return human-formatted output          # or a raw dict that we need to serialize in JSON for printing          res = func(**args) diff --git a/python/vyos/util.py b/python/vyos/util.py index 6a828c0ac..110da3be5 100644 --- a/python/vyos/util.py +++ b/python/vyos/util.py @@ -348,9 +348,11 @@ def colon_separated_to_dict(data_string, uniquekeys=False):          l = l.strip()          if l:              match = re.match(key_value_re, l) -            if match: +            if match and (len(match.groups()) == 2):                  key = match.groups()[0].strip()                  value = match.groups()[1].strip() +            else: +                raise ValueError(f"""Line "{l}" could not be parsed a colon-separated pair """, l)              if key in data.keys():                  if uniquekeys:                      raise ValueError("Data string has duplicate keys: {0}".format(key)) diff --git a/smoketest/scripts/cli/test_interfaces_ethernet.py b/smoketest/scripts/cli/test_interfaces_ethernet.py index ed611062a..e53413f0d 100755 --- a/smoketest/scripts/cli/test_interfaces_ethernet.py +++ b/smoketest/scripts/cli/test_interfaces_ethernet.py @@ -160,7 +160,7 @@ class EthernetInterfaceTest(BasicInterfaceTest.TestCase):                  self.assertFalse(is_intf_addr_assigned(intf, addr['addr']))      def test_offloading_rps(self): -        # enable RPS on all available CPUs, RPS works woth a CPU bitmask, +        # enable RPS on all available CPUs, RPS works with a CPU bitmask,          # where each bit represents a CPU (core/thread). The formula below          # expands to rps_cpus = 255 for a 8 core system          rps_cpus = (1 << os.cpu_count()) -1 diff --git a/smoketest/scripts/cli/test_load_balancning_wan.py b/smoketest/scripts/cli/test_load_balancing_wan.py index 23020b9b1..33c69c595 100755 --- a/smoketest/scripts/cli/test_load_balancning_wan.py +++ b/smoketest/scripts/cli/test_load_balancing_wan.py @@ -46,7 +46,6 @@ def cmd_in_netns(netns, cmd):  def delete_netns(name):      return call(f'sudo ip netns del {name}') -  class TestLoadBalancingWan(VyOSUnitTestSHIM.TestCase):      @classmethod      def setUpClass(cls): @@ -61,7 +60,6 @@ class TestLoadBalancingWan(VyOSUnitTestSHIM.TestCase):          self.cli_commit()      def test_table_routes(self): -          ns1 = 'ns201'          ns2 = 'ns202'          ns3 = 'ns203' @@ -79,6 +77,7 @@ class TestLoadBalancingWan(VyOSUnitTestSHIM.TestCase):          create_veth_pair(iface1, container_iface1)          create_veth_pair(iface2, container_iface2)          create_veth_pair(iface3, container_iface3) +          move_interface_to_netns(container_iface1, ns1)          move_interface_to_netns(container_iface2, ns2)          move_interface_to_netns(container_iface3, ns3) @@ -125,7 +124,7 @@ class TestLoadBalancingWan(VyOSUnitTestSHIM.TestCase):          self.assertEqual(tmp, original)          # Delete veth interfaces and netns -        for iface in [iface1, iface2]: +        for iface in [iface1, iface2, iface3, container_iface1, container_iface2, container_iface3]:              call(f'sudo ip link del dev {iface}')          delete_netns(ns1) @@ -196,9 +195,10 @@ class TestLoadBalancingWan(VyOSUnitTestSHIM.TestCase):          call(f'sudo ip address add 203.0.113.10/24 dev {iface1}')          call(f'sudo ip address add 192.0.2.10/24 dev {iface2}')          call(f'sudo ip address add 198.51.100.10/24 dev {iface3}') -        call(f'sudo ip link set dev {iface1} up') -        call(f'sudo ip link set dev {iface2} up') -        call(f'sudo ip link set dev {iface3} up') + +        for iface in [iface1, iface2, iface3]: +            call(f'sudo ip link set dev {iface} up') +          cmd_in_netns(ns1, f'ip link set {container_iface1} name eth0')          cmd_in_netns(ns2, f'ip link set {container_iface2} name eth0')          cmd_in_netns(ns3, f'ip link set {container_iface3} name eth0') @@ -247,12 +247,11 @@ class TestLoadBalancingWan(VyOSUnitTestSHIM.TestCase):          self.assertEqual(tmp, nat_vyos_pre_snat_hook)          # Delete veth interfaces and netns -        for iface in [iface1, iface2]: +        for iface in [iface1, iface2, iface3, container_iface1, container_iface2, container_iface3]:              call(f'sudo ip link del dev {iface}')          delete_netns(ns1)          delete_netns(ns2) -  if __name__ == '__main__':      unittest.main(verbosity=2) diff --git a/smoketest/scripts/cli/test_protocols_ospf.py b/smoketest/scripts/cli/test_protocols_ospf.py index 8dd0160d3..581959b15 100755 --- a/smoketest/scripts/cli/test_protocols_ospf.py +++ b/smoketest/scripts/cli/test_protocols_ospf.py @@ -75,6 +75,10 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase):          self.cli_set(base_path + ['log-adjacency-changes', 'detail'])          self.cli_set(base_path + ['default-metric', metric])          self.cli_set(base_path + ['passive-interface', 'default']) +        self.cli_set(base_path + ['area', '10', 'area-type', 'stub']) +        self.cli_set(base_path + ['area', '10', 'network', '10.0.0.0/16']) +        self.cli_set(base_path + ['area', '10', 'range', '10.0.1.0/24']) +        self.cli_set(base_path + ['area', '10', 'range', '10.0.2.0/24', 'not-advertise'])          # commit changes          self.cli_commit() @@ -90,6 +94,11 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase):          self.assertIn(f' capability opaque', frrconfig)          self.assertIn(f' default-metric {metric}', frrconfig)          self.assertIn(f' passive-interface default', frrconfig) +        self.assertIn(f' area 10 stub', frrconfig) +        self.assertIn(f' network 10.0.0.0/16 area 10', frrconfig) +        self.assertIn(f' area 10 range 10.0.1.0/24', frrconfig) +        self.assertNotIn(f' area 10 range 10.0.1.0/24 not-advertise', frrconfig) +        self.assertIn(f' area 10 range 10.0.2.0/24 not-advertise', frrconfig)      def test_ospf_03_access_list(self): diff --git a/smoketest/scripts/cli/test_service_dhcpv6-relay.py b/smoketest/scripts/cli/test_service_dhcpv6-relay.py index fc206435b..8bb58d296 100755 --- a/smoketest/scripts/cli/test_service_dhcpv6-relay.py +++ b/smoketest/scripts/cli/test_service_dhcpv6-relay.py @@ -1,6 +1,6 @@  #!/usr/bin/env python3  # -# Copyright (C) 2020 VyOS maintainers and contributors +# Copyright (C) 2020-2023 VyOS maintainers and contributors  #  # This program is free software; you can redistribute it and/or modify  # it under the terms of the GNU General Public License version 2 or later as @@ -34,22 +34,30 @@ listen_addr = '2001:db8:ffff::1/64'  interfaces = []  class TestServiceDHCPv6Relay(VyOSUnitTestSHIM.TestCase): -    def setUp(self): -        for tmp in interfaces: +    @classmethod +    def setUpClass(cls): +        super(TestServiceDHCPv6Relay, cls).setUpClass() + +        # ensure we can also run this test on a live system - so lets clean +        # out the current configuration :) +        cls.cli_delete(cls, base_path) + +        for tmp in Section.interfaces('ethernet', vlan=False): +            interfaces.append(tmp)              listen = listen_addr              if tmp == upstream_if:                  listen = upstream_if_addr -            self.cli_set(['interfaces', 'ethernet', tmp, 'address', listen]) +            cls.cli_set(cls, ['interfaces', 'ethernet', tmp, 'address', listen]) -    def tearDown(self): -        self.cli_delete(base_path) +    @classmethod +    def tearDownClass(cls):          for tmp in interfaces:              listen = listen_addr              if tmp == upstream_if:                  listen = upstream_if_addr -            self.cli_delete(['interfaces', 'ethernet', tmp, 'address', listen]) +            cls.cli_delete(cls, ['interfaces', 'ethernet', tmp, 'address', listen]) -        self.cli_commit() +        super(TestServiceDHCPv6Relay, cls).tearDownClass()      def test_relay_default(self):          dhcpv6_server = '2001:db8::ffff' @@ -100,9 +108,5 @@ class TestServiceDHCPv6Relay(VyOSUnitTestSHIM.TestCase):          self.assertTrue(process_named_running(PROCESS_NAME))  if __name__ == '__main__': -    for tmp in Section.interfaces('ethernet'): -        if '.' not in tmp: -            interfaces.append(tmp) -      unittest.main(verbosity=2) diff --git a/smoketest/scripts/cli/test_system_ntp.py b/smoketest/scripts/cli/test_service_ntp.py index a0806acf0..d4793adb6 100755 --- a/smoketest/scripts/cli/test_system_ntp.py +++ b/smoketest/scripts/cli/test_service_ntp.py @@ -1,6 +1,6 @@  #!/usr/bin/env python3  # -# Copyright (C) 2019-2022 VyOS maintainers and contributors +# Copyright (C) 2019-2023 VyOS maintainers and contributors  #  # This program is free software; you can redistribute it and/or modify  # it under the terms of the GNU General Public License version 2 or later as @@ -19,14 +19,12 @@ import unittest  from base_vyostest_shim import VyOSUnitTestSHIM  from vyos.configsession import ConfigSessionError -from vyos.template import address_from_cidr -from vyos.template import netmask_from_cidr -from vyos.util import read_file +from vyos.util import cmd  from vyos.util import process_named_running -PROCESS_NAME = 'ntpd' -NTP_CONF = '/run/ntpd/ntpd.conf' -base_path = ['system', 'ntp'] +PROCESS_NAME = 'chronyd' +NTP_CONF = '/run/chrony/chrony.conf' +base_path = ['service', 'ntp']  class TestSystemNTP(VyOSUnitTestSHIM.TestCase):      @classmethod @@ -38,6 +36,8 @@ class TestSystemNTP(VyOSUnitTestSHIM.TestCase):          cls.cli_delete(cls, base_path)      def tearDown(self): +        self.assertTrue(process_named_running(PROCESS_NAME)) +          self.cli_delete(base_path)          self.cli_commit() @@ -46,7 +46,7 @@ class TestSystemNTP(VyOSUnitTestSHIM.TestCase):      def test_01_ntp_options(self):          # Test basic NTP support with multiple servers and their options          servers = ['192.0.2.1', '192.0.2.2'] -        options = ['noselect', 'preempt', 'prefer'] +        options = ['noselect', 'prefer']          pools = ['pool.vyos.io']          for server in servers: @@ -61,12 +61,14 @@ class TestSystemNTP(VyOSUnitTestSHIM.TestCase):          self.cli_commit()          # Check generated configuration -        config = read_file(NTP_CONF) -        self.assertIn('driftfile /var/lib/ntp/ntp.drift', config) -        self.assertIn('restrict default noquery nopeer notrap nomodify', config) -        self.assertIn('restrict source nomodify notrap noquery', config) -        self.assertIn('restrict 127.0.0.1', config) -        self.assertIn('restrict -6 ::1', config) +        # this file must be read with higher permissions +        config = cmd(f'sudo cat {NTP_CONF}') +        self.assertIn('driftfile /run/chrony/drift', config) +        self.assertIn('dumpdir /run/chrony', config) +        self.assertIn('clientloglimit 1048576', config) +        self.assertIn('rtcsync', config) +        self.assertIn('makestep 1.0 3', config) +        self.assertIn('leapsectz right/UTC', config)          for server in servers:              self.assertIn(f'server {server} iburst ' + ' '.join(options), config) @@ -80,9 +82,9 @@ class TestSystemNTP(VyOSUnitTestSHIM.TestCase):          for listen in listen_address:              self.cli_set(base_path + ['listen-address', listen]) -        networks = ['192.0.2.0/24', '2001:db8:1000::/64'] +        networks = ['192.0.2.0/24', '2001:db8:1000::/64', '100.64.0.0', '2001:db8::ffff']          for network in networks: -            self.cli_set(base_path + ['allow-clients', 'address', network]) +            self.cli_set(base_path + ['allow-client', 'address', network])          # Verify "NTP server not configured" verify() statement          with self.assertRaises(ConfigSessionError): @@ -95,18 +97,14 @@ class TestSystemNTP(VyOSUnitTestSHIM.TestCase):          self.cli_commit()          # Check generated client address configuration -        config = read_file(NTP_CONF) -        self.assertIn('restrict default ignore', config) - +        # this file must be read with higher permissions +        config = cmd(f'sudo cat {NTP_CONF}')          for network in networks: -            network_address = address_from_cidr(network) -            network_netmask = netmask_from_cidr(network) -            self.assertIn(f'restrict {network_address} mask {network_netmask} nomodify notrap nopeer', config) +            self.assertIn(f'allow {network}', config)          # Check listen address -        self.assertIn('interface ignore wildcard', config)          for listen in listen_address: -            self.assertIn(f'interface listen {listen}', config) +            self.assertIn(f'bindaddress {listen}', config)      def test_03_ntp_interface(self):          interfaces = ['eth0', 'eth1'] @@ -120,10 +118,24 @@ class TestSystemNTP(VyOSUnitTestSHIM.TestCase):          self.cli_commit()          # Check generated client address configuration -        config = read_file(NTP_CONF) -        self.assertIn('interface ignore wildcard', config) +        # this file must be read with higher permissions +        config = cmd(f'sudo cat {NTP_CONF}')          for interface in interfaces: -            self.assertIn(f'interface listen {interface}', config) +            self.assertIn(f'binddevice {interface}', config) + +    def test_04_ntp_vrf(self): +        vrf_name = 'vyos-mgmt' + +        self.cli_set(['vrf', 'name', vrf_name, 'table', '12345']) +        self.cli_set(base_path + ['vrf', vrf_name]) + +        servers = ['time1.vyos.net', 'time2.vyos.net'] +        for server in servers: +            self.cli_set(base_path + ['server', server]) + +        self.cli_commit() + +        self.cli_delete(['vrf', 'name', vrf_name])  if __name__ == '__main__':      unittest.main(verbosity=2) diff --git a/src/conf_mode/flow_accounting_conf.py b/src/conf_mode/flow_accounting_conf.py index 7e16235c1..f67f1710e 100755 --- a/src/conf_mode/flow_accounting_conf.py +++ b/src/conf_mode/flow_accounting_conf.py @@ -38,7 +38,7 @@ airbag.enable()  uacctd_conf_path = '/run/pmacct/uacctd.conf'  systemd_service = 'uacctd.service' -systemd_override = f'/etc/systemd/system/{systemd_service}.d/override.conf' +systemd_override = f'/run/systemd/system/{systemd_service}.d/override.conf'  nftables_nflog_table = 'raw'  nftables_nflog_chain = 'VYOS_CT_PREROUTING_HOOK'  egress_nftables_nflog_table = 'inet mangle' @@ -192,7 +192,7 @@ def verify(flow_config):                      raise ConfigError("All sFlow servers must use the same IP protocol")              else:                  sflow_collector_ipver = ip_address(server).version -	 +          # check if vrf is defined for Sflow          sflow_vrf = None          if 'vrf' in flow_config: diff --git a/src/conf_mode/https.py b/src/conf_mode/https.py index 7cd7ea42e..ce5e63928 100755 --- a/src/conf_mode/https.py +++ b/src/conf_mode/https.py @@ -37,7 +37,7 @@ from vyos import airbag  airbag.enable()  config_file = '/etc/nginx/sites-available/default' -systemd_override = r'/etc/systemd/system/nginx.service.d/override.conf' +systemd_override = r'/run/systemd/system/nginx.service.d/override.conf'  cert_dir = '/etc/ssl/certs'  key_dir = '/etc/ssl/private'  certbot_dir = vyos.defaults.directories['certbot'] diff --git a/src/conf_mode/ntp.py b/src/conf_mode/ntp.py index 0ecb4d736..92cb73aab 100755 --- a/src/conf_mode/ntp.py +++ b/src/conf_mode/ntp.py @@ -1,6 +1,6 @@  #!/usr/bin/env python3  # -# Copyright (C) 2018-2022 VyOS maintainers and contributors +# Copyright (C) 2018-2023 VyOS maintainers and contributors  #  # This program is free software; you can redistribute it and/or modify  # it under the terms of the GNU General Public License version 2 or later as @@ -21,26 +21,29 @@ from vyos.configdict import is_node_changed  from vyos.configverify import verify_vrf  from vyos.configverify import verify_interface_exists  from vyos.util import call +from vyos.util import chmod_750  from vyos.util import get_interface_config  from vyos.template import render  from vyos import ConfigError  from vyos import airbag  airbag.enable() -config_file = r'/run/ntpd/ntpd.conf' -systemd_override = r'/etc/systemd/system/ntp.service.d/override.conf' +config_file = r'/run/chrony/chrony.conf' +systemd_override = r'/run/systemd/system/chrony.service.d/override.conf' +user_group = '_chrony'  def get_config(config=None):      if config:          conf = config      else:          conf = Config() -    base = ['system', 'ntp'] +    base = ['service', 'ntp']      if not conf.exists(base):          return None      ntp = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True)      ntp['config_file'] = config_file +    ntp['user'] = user_group      tmp = is_node_changed(conf, base + ['vrf'])      if tmp: ntp.update({'restart_required': {}}) @@ -52,7 +55,7 @@ def verify(ntp):      if not ntp:          return None -    if 'allow_clients' in ntp and 'server' not in ntp: +    if 'server' not in ntp:          raise ConfigError('NTP server not configured')      verify_vrf(ntp) @@ -77,13 +80,17 @@ def generate(ntp):      if not ntp:          return None -    render(config_file, 'ntp/ntpd.conf.j2', ntp) -    render(systemd_override, 'ntp/override.conf.j2', ntp) +    render(config_file, 'chrony/chrony.conf.j2', ntp, user=user_group, group=user_group) +    render(systemd_override, 'chrony/override.conf.j2', ntp, user=user_group, group=user_group) + +    # Ensure proper permission for chrony command socket +    config_dir = os.path.dirname(config_file) +    chmod_750(config_dir)      return None  def apply(ntp): -    systemd_service = 'ntp.service' +    systemd_service = 'chrony.service'      # Reload systemd manager configuration      call('systemctl daemon-reload') diff --git a/src/conf_mode/protocols_failover.py b/src/conf_mode/protocols_failover.py index 048ba7a89..85e984afe 100755 --- a/src/conf_mode/protocols_failover.py +++ b/src/conf_mode/protocols_failover.py @@ -31,7 +31,7 @@ airbag.enable()  service_name = 'vyos-failover'  service_conf = Path(f'/run/{service_name}.conf') -systemd_service = '/etc/systemd/system/vyos-failover.service' +systemd_service = '/run/systemd/system/vyos-failover.service'  rt_proto_failover = '/etc/iproute2/rt_protos.d/failover.conf' diff --git a/src/conf_mode/protocols_ospfv3.py b/src/conf_mode/protocols_ospfv3.py index ee4eaf59d..ed0a8fba2 100755 --- a/src/conf_mode/protocols_ospfv3.py +++ b/src/conf_mode/protocols_ospfv3.py @@ -117,6 +117,10 @@ def verify(ospfv3):              if 'area_type' in area_config:                  if len(area_config['area_type']) > 1:                      raise ConfigError(f'Can only configure one area-type for OSPFv3 area "{area}"!') +            if 'range' in area_config: +                for range, range_config in area_config['range'].items(): +                    if {'not_advertise', 'advertise'} <= range_config.keys(): +                        raise ConfigError(f'"not-advertise" and "advertise" for "range {range}" cannot be both configured at the same time!')      if 'interface' in ospfv3:          for interface, interface_config in ospfv3['interface'].items(): diff --git a/src/conf_mode/service_console-server.py b/src/conf_mode/service_console-server.py index ee4fe42ab..60eff6543 100755 --- a/src/conf_mode/service_console-server.py +++ b/src/conf_mode/service_console-server.py @@ -27,7 +27,7 @@ from vyos.xml import defaults  from vyos import ConfigError  config_file = '/run/conserver/conserver.cf' -dropbear_systemd_file = '/etc/systemd/system/dropbear@{port}.service.d/override.conf' +dropbear_systemd_file = '/run/systemd/system/dropbear@{port}.service.d/override.conf'  def get_config(config=None):      if config: diff --git a/src/conf_mode/service_monitoring_telegraf.py b/src/conf_mode/service_monitoring_telegraf.py index aafece47a..363408679 100755 --- a/src/conf_mode/service_monitoring_telegraf.py +++ b/src/conf_mode/service_monitoring_telegraf.py @@ -38,7 +38,7 @@ cache_dir = f'/etc/telegraf/.cache'  config_telegraf = f'/run/telegraf/telegraf.conf'  custom_scripts_dir = '/etc/telegraf/custom_scripts'  syslog_telegraf = '/etc/rsyslog.d/50-telegraf.conf' -systemd_override = '/etc/systemd/system/telegraf.service.d/10-override.conf' +systemd_override = '/run/systemd/system/telegraf.service.d/10-override.conf'  def get_nft_filter_chains():      """ Get nft chains for table filter """ diff --git a/src/conf_mode/service_sla.py b/src/conf_mode/service_sla.py index e7c3ca59c..b1e22f37b 100755 --- a/src/conf_mode/service_sla.py +++ b/src/conf_mode/service_sla.py @@ -27,15 +27,13 @@ from vyos import ConfigError  from vyos import airbag  airbag.enable() -  owamp_config_dir = '/etc/owamp-server'  owamp_config_file = f'{owamp_config_dir}/owamp-server.conf' -systemd_override_owamp = r'/etc/systemd/system/owamp-server.d/20-override.conf' +systemd_override_owamp = r'/run/systemd/system/owamp-server.d/20-override.conf'  twamp_config_dir = '/etc/twamp-server'  twamp_config_file = f'{twamp_config_dir}/twamp-server.conf' -systemd_override_twamp = r'/etc/systemd/system/twamp-server.d/20-override.conf' - +systemd_override_twamp = r'/run/systemd/system/twamp-server.d/20-override.conf'  def get_config(config=None):      if config: diff --git a/src/conf_mode/service_webproxy.py b/src/conf_mode/service_webproxy.py index 41a1deaa3..658e496a6 100755 --- a/src/conf_mode/service_webproxy.py +++ b/src/conf_mode/service_webproxy.py @@ -246,7 +246,7 @@ def apply(proxy):      if os.path.exists(squidguard_db_dir):          chmod_755(squidguard_db_dir) -    call('systemctl restart squid.service') +    call('systemctl reload-or-restart squid.service')      return None diff --git a/src/conf_mode/snmp.py b/src/conf_mode/snmp.py index 5cd24db32..914ec245c 100755 --- a/src/conf_mode/snmp.py +++ b/src/conf_mode/snmp.py @@ -40,7 +40,7 @@ config_file_client  = r'/etc/snmp/snmp.conf'  config_file_daemon  = r'/etc/snmp/snmpd.conf'  config_file_access  = r'/usr/share/snmp/snmpd.conf'  config_file_user    = r'/var/lib/snmp/snmpd.conf' -systemd_override    = r'/etc/systemd/system/snmpd.service.d/override.conf' +systemd_override    = r'/run/systemd/system/snmpd.service.d/override.conf'  systemd_service     = 'snmpd.service'  def get_config(config=None): diff --git a/src/conf_mode/ssh.py b/src/conf_mode/ssh.py index 8746cc701..8de0617af 100755 --- a/src/conf_mode/ssh.py +++ b/src/conf_mode/ssh.py @@ -32,7 +32,7 @@ from vyos import airbag  airbag.enable()  config_file = r'/run/sshd/sshd_config' -systemd_override = r'/etc/systemd/system/ssh.service.d/override.conf' +systemd_override = r'/run/systemd/system/ssh.service.d/override.conf'  sshguard_config_file = '/etc/sshguard/sshguard.conf'  sshguard_whitelist = '/etc/sshguard/whitelist' diff --git a/src/conf_mode/vpn_ipsec.py b/src/conf_mode/vpn_ipsec.py index b79e9847a..3af2af4d9 100755 --- a/src/conf_mode/vpn_ipsec.py +++ b/src/conf_mode/vpn_ipsec.py @@ -95,6 +95,7 @@ def get_config(config=None):      del default_values['esp_group']      del default_values['ike_group']      del default_values['remote_access'] +    del default_values['site_to_site']      ipsec = dict_merge(default_values, ipsec)      if 'esp_group' in ipsec: @@ -143,6 +144,14 @@ def get_config(config=None):              ipsec['remote_access']['radius']['server'][server] = dict_merge(default_values,                  ipsec['remote_access']['radius']['server'][server]) +    # XXX: T2665: we can not safely rely on the defaults() when there are +    # tagNodes in place, it is better to blend in the defaults manually. +    if dict_search('site_to_site.peer', ipsec): +        default_values = defaults(base + ['site-to-site', 'peer']) +        for peer in ipsec['site_to_site']['peer']: +            ipsec['site_to_site']['peer'][peer] = dict_merge(default_values, +              ipsec['site_to_site']['peer'][peer]) +      ipsec['dhcp_no_address'] = {}      ipsec['install_routes'] = 'no' if conf.exists(base + ["options", "disable-route-autoinstall"]) else default_install_routes      ipsec['interface_change'] = leaf_node_changed(conf, base + ['interface']) diff --git a/src/migration-scripts/ntp/1-to-2 b/src/migration-scripts/ntp/1-to-2 new file mode 100755 index 000000000..4a701e7e5 --- /dev/null +++ b/src/migration-scripts/ntp/1-to-2 @@ -0,0 +1,67 @@ +#!/usr/bin/env python3 + +# Copyright (C) 2023 VyOS maintainers and contributors +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 or later as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program.  If not, see <http://www.gnu.org/licenses/>. + +# T3008: move from ntpd to chrony and migrate "system ntp" to "service ntp" + +import sys + +from vyos.configtree import ConfigTree + +if (len(sys.argv) < 1): +    print("Must specify file name!") +    sys.exit(1) + +file_name = sys.argv[1] + +with open(file_name, 'r') as f: +    config_file = f.read() + +config = ConfigTree(config_file) + +base_path = ['system', 'ntp'] +new_base_path = ['service', 'ntp'] +if not config.exists(base_path): +    # Nothing to do +    sys.exit(0) + +# copy "system ntp" to "service ntp" +config.copy(base_path, new_base_path) +config.delete(base_path) + +# chrony does not support the preempt option, drop it +for server in config.list_nodes(new_base_path + ['server']): +    server_base =  new_base_path + ['server', server] +    if config.exists(server_base + ['preempt']): +        config.delete(server_base + ['preempt']) + +# Rename "allow-clients" -> "allow-client" +if config.exists(new_base_path + ['allow-clients']): +    config.rename(new_base_path + ['allow-clients'], 'allow-client') + +# By default VyOS 1.3 allowed NTP queries for all networks - in chrony we +# explicitly disable this behavior and clients need to be specified using the +# allow-client CLI option. In order to be fully backwards compatible, we specify +# 0.0.0.0/0 and ::/0 as allow networks if not specified otherwise explicitly. +if not config.exists(new_base_path + ['allow-client']): +    config.set(new_base_path + ['allow-client', 'address'], value='0.0.0.0/0', replace=False) +    config.set(new_base_path + ['allow-client', 'address'], value='::/0', replace=False) + +try: +    with open(file_name, 'w') as f: +        f.write(config.to_string()) +except OSError as e: +    print("Failed to save the modified config: {}".format(e)) +    sys.exit(1) diff --git a/src/op_mode/lldp.py b/src/op_mode/lldp.py new file mode 100755 index 000000000..dc2b1e0b5 --- /dev/null +++ b/src/op_mode/lldp.py @@ -0,0 +1,138 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2023 VyOS maintainers and contributors +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 or later as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program.  If not, see <http://www.gnu.org/licenses/>. + +import jmespath +import json +import sys +import typing + +from tabulate import tabulate + +from vyos.configquery import ConfigTreeQuery +from vyos.util import cmd +from vyos.util import dict_search + +import vyos.opmode +unconf_message = 'LLDP is not configured' +capability_codes = """Capability Codes: R - Router, B - Bridge, W - Wlan r - Repeater, S - Station +                  D - Docsis, T - Telephone, O - Other + +""" + +def _verify(func): +    """Decorator checks if LLDP config exists""" +    from functools import wraps + +    @wraps(func) +    def _wrapper(*args, **kwargs): +        config = ConfigTreeQuery() +        if not config.exists(['service', 'lldp']): +            raise vyos.opmode.UnconfiguredSubsystem(unconf_message) +        return func(*args, **kwargs) +    return _wrapper + +def _get_raw_data(interface=None, detail=False): +    """ +    If interface name is not set - get all interfaces +    """ +    tmp = 'lldpcli -f json show neighbors' +    if detail: +        tmp += f' details' +    if interface: +        tmp += f' ports {interface}' +    output = cmd(tmp) +    data = json.loads(output) +    if not data: +        return [] +    return data + +def _get_formatted_output(raw_data): +    data_entries = [] +    for neighbor in dict_search('lldp.interface', raw_data): +        for local_if, values in neighbor.items(): +            tmp = [] + +            # Device field +            if 'chassis' in values: +                tmp.append(next(iter(values['chassis']))) +            else: +                tmp.append('') + +            # Local Port field +            tmp.append(local_if) + +            # Protocol field +            tmp.append(values['via']) + +            # Capabilities +            cap = '' +            capabilities = jmespath.search('chassis.[*][0][0].capability', values) +            if capabilities: +                for capability in capabilities: +                    if capability['enabled']: +                        if capability['type'] == 'Router': +                            cap += 'R' +                        if capability['type'] == 'Bridge': +                            cap += 'B' +                        if capability['type'] == 'Wlan': +                            cap += 'W' +                        if capability['type'] == 'Station': +                            cap += 'S' +                        if capability['type'] == 'Repeater': +                            cap += 'r' +                        if capability['type'] == 'Telephone': +                            cap += 'T' +                        if capability['type'] == 'Docsis': +                            cap += 'D' +                        if capability['type'] == 'Other': +                            cap += 'O' +            tmp.append(cap) + +            # Remote software platform +            platform = jmespath.search('chassis.[*][0][0].descr', values) +            tmp.append(platform[:37]) + +            # Remote interface +            interface = jmespath.search('port.descr', values) +            if not interface: +                interface = jmespath.search('port.id.value', values) +            if not interface: +                interface = 'Unknown' +            tmp.append(interface) + +            # Add individual neighbor to output list +            data_entries.append(tmp) + +    headers = ["Device", "Local Port", "Protocol", "Capability", "Platform", "Remote Port"] +    output = tabulate(data_entries, headers, numalign="left") +    return capability_codes + output + +@_verify +def show_neighbors(raw: bool, interface: typing.Optional[str], detail: typing.Optional[bool]): +    lldp_data = _get_raw_data(interface=interface, detail=detail) +    if raw: +        return lldp_data +    else: +        return _get_formatted_output(lldp_data) + +if __name__ == "__main__": +    try: +        res = vyos.opmode.run(sys.modules[__name__]) +        if res: +            print(res) +    except (ValueError, vyos.opmode.Error) as e: +        print(e) +        sys.exit(1) diff --git a/src/op_mode/lldp_op.py b/src/op_mode/lldp_op.py deleted file mode 100755 index 17f6bf552..000000000 --- a/src/op_mode/lldp_op.py +++ /dev/null @@ -1,127 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright (C) 2019-2020 VyOS maintainers and contributors -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2 or later as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program.  If not, see <http://www.gnu.org/licenses/>. - -import argparse -import jinja2 -import json - -from sys import exit -from tabulate import tabulate - -from vyos.util import cmd -from vyos.config import Config - -parser = argparse.ArgumentParser() -parser.add_argument("-a", "--all", action="store_true", help="Show LLDP neighbors on all interfaces") -parser.add_argument("-d", "--detail", action="store_true", help="Show detailes LLDP neighbor information on all interfaces") -parser.add_argument("-i", "--interface", action="store", help="Show LLDP neighbors on specific interface") - -# Please be careful if you edit the template. -lldp_out = """Capability Codes: R - Router, B - Bridge, W - Wlan r - Repeater, S - Station -                  D - Docsis, T - Telephone, O - Other - -Device ID                 Local     Proto  Cap   Platform             Port ID ----------                 -----     -----  ---   --------             ------- -{% for neighbor in neighbors %} -{%   for local_if, info in neighbor.items() %} -{{ "%-25s" | format(info.chassis) }} {{ "%-9s" | format(local_if) }} {{ "%-6s" | format(info.proto) }} {{ "%-5s" | format(info.capabilities) }} {{ "%-20s" | format(info.platform[:18]) }} {{ info.remote_if }} -{%   endfor %} -{% endfor %} -""" - -def get_neighbors(): -    return cmd('/usr/sbin/lldpcli -f json show neighbors') - -def parse_data(data, interface): -    output = [] -    if not isinstance(data, list): -        data = [data] - -    for neighbor in data: -        for local_if, values in neighbor.items(): -            if interface is not None and local_if != interface: -                continue -            cap = '' -            for chassis, c_value in values.get('chassis', {}).items(): -                # bail out early if no capabilities found -                if 'capability' not in c_value: -                    continue -                capabilities = c_value['capability'] -                if isinstance(capabilities, dict): -                    capabilities = [capabilities] - -                for capability in capabilities: -                    if capability['enabled']: -                        if capability['type'] == 'Router': -                            cap += 'R' -                        if capability['type'] == 'Bridge': -                            cap += 'B' -                        if capability['type'] == 'Wlan': -                            cap += 'W' -                        if capability['type'] == 'Station': -                            cap += 'S' -                        if capability['type'] == 'Repeater': -                            cap += 'r' -                        if capability['type'] == 'Telephone': -                            cap += 'T' -                        if capability['type'] == 'Docsis': -                            cap += 'D' -                        if capability['type'] == 'Other': -                            cap += 'O' - -            remote_if = 'Unknown' -            if 'descr' in values.get('port', {}): -                remote_if = values.get('port', {}).get('descr') -            elif 'id' in values.get('port', {}): -                remote_if = values.get('port', {}).get('id').get('value', 'Unknown') - -            output.append({local_if: {'chassis': chassis, -                                       'remote_if': remote_if, -                                       'proto': values.get('via','Unknown'), -                                       'platform': c_value.get('descr', 'Unknown'), -                                       'capabilities': cap}}) - -    output = {'neighbors': output} -    return output - -if __name__ == '__main__': -    args = parser.parse_args() -    tmp = { 'neighbors' : [] } - -    c = Config() -    if not c.exists_effective(['service', 'lldp']): -        print('Service LLDP is not configured') -        exit(0) - -    if args.detail: -        print(cmd('/usr/sbin/lldpctl -f plain')) -        exit(0) -    elif args.all or args.interface: -        tmp = json.loads(get_neighbors()) -        neighbors = dict() - -        if 'interface' in tmp.get('lldp'): -            neighbors = tmp['lldp']['interface'] - -    else: -        parser.print_help() -        exit(1) - -    tmpl = jinja2.Template(lldp_out, trim_blocks=True) -    config_text = tmpl.render(parse_data(neighbors, interface=args.interface)) -    print(config_text) - -    exit(0) diff --git a/src/op_mode/show_ntp.sh b/src/op_mode/show_ntp.sh index e9dd6c5c9..85f8eda15 100755 --- a/src/op_mode/show_ntp.sh +++ b/src/op_mode/show_ntp.sh @@ -1,39 +1,34 @@  #!/bin/sh -basic=0 -info=0 +sourcestats=0 +tracking=0  while [[ "$#" -gt 0 ]]; do      case $1 in -        --info) info=1 ;; -        --basic) basic=1 ;; -        --server) server=$2; shift ;; +        --sourcestats) sourcestats=1 ;; +        --tracking) tracking=1 ;;          *) echo "Unknown parameter passed: $1" ;;      esac      shift  done -if ! ps -C ntpd &>/dev/null; then +if ! ps -C chronyd &>/dev/null; then      echo NTP daemon disabled      exit 1  fi -PID=$(pgrep ntpd) -VRF_NAME=$(ip vrf identify ${PID}) +PID=$(pgrep chronyd | head -n1) +VRF_NAME=$(ip vrf identify )  if [ ! -z ${VRF_NAME} ]; then      VRF_CMD="sudo ip vrf exec ${VRF_NAME}"  fi -if [ $basic -eq 1 ]; then -    $VRF_CMD ntpq -n -c peers -elif [ $info -eq 1 ]; then -    echo "=== sysingo ===" -    $VRF_CMD ntpq -n -c sysinfo -    echo -    echo "=== kerninfo ===" -    $VRF_CMD ntpq -n -c kerninfo -elif [ ! -z $server ]; then -    $VRF_CMD /usr/sbin/ntpdate -q $server +if [ $sourcestats -eq 1 ]; then +    $VRF_CMD chronyc sourcestats -v +elif [ $tracking -eq 1 ]; then +    $VRF_CMD chronyc tracking -v +else +    echo "Unknown option"  fi | 
