diff options
168 files changed, 2297 insertions, 1133 deletions
| @@ -65,9 +65,9 @@ op_mode_definitions: $(op_xml_obj)  	rm -f $(OP_TMPL_DIR)/generate/node.def  	rm -f $(OP_TMPL_DIR)/monitor/node.def  	rm -f $(OP_TMPL_DIR)/set/node.def -	rm -f $(OP_TMPL_DIR)/show/interfaces/node.def  	rm -f $(OP_TMPL_DIR)/show/node.def  	rm -f $(OP_TMPL_DIR)/show/system/node.def +	rm -f $(OP_TMPL_DIR)/show/tech-support/node.def  	# XXX: ping and traceroute must be able to recursivly call itself as the  	# options are provided from the script itself diff --git a/data/configd-include.json b/data/configd-include.json index 456211caa..2f1d39006 100644 --- a/data/configd-include.json +++ b/data/configd-include.json @@ -85,6 +85,5 @@  "vpn_l2tp.py",  "vpn_pptp.py",  "vpn_sstp.py", -"vrf.py", -"vrf_vni.py" +"vrf.py"  ] diff --git a/data/templates/accel-ppp/pptp.config.j2 b/data/templates/accel-ppp/pptp.config.j2 index 442830b6b..78a629d2d 100644 --- a/data/templates/accel-ppp/pptp.config.j2 +++ b/data/templates/accel-ppp/pptp.config.j2 @@ -93,10 +93,15 @@ bind={{ radius_source_address }}  gw-ip-address={{ gw_ip }}  {% endif %} -{% if radius_shaper_attr %} +{% if radius_shaper_enable %}  [shaper]  verbose=1 +{%     if radius_shaper_attr %}  attr={{ radius_shaper_attr }} +{%     endif %} +{%     if radius_shaper_multiplier %} +rate-multiplier={{ radius_shaper_multiplier }} +{%     endif %}  {%     if radius_shaper_vendor %}  vendor={{ radius_shaper_vendor }}  {%     endif %} diff --git a/data/templates/container/containers.conf.j2 b/data/templates/container/containers.conf.j2 index 9f66aed27..c635ca213 100644 --- a/data/templates/container/containers.conf.j2 +++ b/data/templates/container/containers.conf.j2 @@ -282,7 +282,7 @@ default_sysctls = [  # Before changing this value all containers must be stopped otherwise it is likely that
  # iptables rules and network interfaces might leak on the host. A reboot will fix this.
  #
 -network_backend = "cni"
 +network_backend = "netavark"
  # Path to directory where CNI plugin binaries are located.
  #
 diff --git a/data/templates/ethernet/wpa_supplicant.conf.j2 b/data/templates/ethernet/wpa_supplicant.conf.j2 index 8f140f6cb..cd35d6d1e 100644 --- a/data/templates/ethernet/wpa_supplicant.conf.j2 +++ b/data/templates/ethernet/wpa_supplicant.conf.j2 @@ -67,6 +67,11 @@ network={      # discards such frames to protect against potential attacks by rogue      # devices, but this option can be used to disable that protection for cases      # where the server/authenticator does not need to be authenticated. -    phase1="allow_canned_success=1" +    # +    # "tls_disable_tlsv1_0=0" is used to allow TLSv1 for compatibility with +    # legacy networks. This follows the behavior of Debian's wpa_supplicant, +    # which includes a custom patch for allowing TLSv1, but the patch currently +    # does not work for VyOS' git builds of wpa_supplicant. +    phase1="allow_canned_success=1 tls_disable_tlsv1_0=0"  } diff --git a/data/templates/firewall/nftables-policy.j2 b/data/templates/firewall/nftables-policy.j2 index 6cb3b2f95..7a89d29e4 100644 --- a/data/templates/firewall/nftables-policy.j2 +++ b/data/templates/firewall/nftables-policy.j2 @@ -11,7 +11,7 @@ table ip vyos_mangle {          type filter hook prerouting priority -150; policy accept;  {% if route is vyos_defined %}  {%     for route_text, conf in route.items() if conf.interface is vyos_defined %} -        iifname { {{ ",".join(conf.interface) }} } counter jump VYOS_PBR_{{ route_text }} +        iifname { {{ conf.interface | join(",") }} } counter jump VYOS_PBR_{{ route_text }}  {%     endfor %}  {% endif %}      } diff --git a/data/templates/frr/isisd.frr.j2 b/data/templates/frr/isisd.frr.j2 index 8df1e9513..3c37e28b9 100644 --- a/data/templates/frr/isisd.frr.j2 +++ b/data/templates/frr/isisd.frr.j2 @@ -25,6 +25,12 @@ interface {{ iface }}  {%         if iface_config.hello_padding is vyos_defined %}   isis hello padding  {%         endif %} +{%         if iface_config.ldp_sync.disable is vyos_defined %} + no isis mpls ldp-sync +{%         elif iface_config.ldp_sync.holddown is vyos_defined %} + isis mpls ldp-sync + isis mpls ldp-sync holddown {{ iface_config.ldp_sync.holddown }} +{%         endif %}  {%         if iface_config.metric is vyos_defined %}   isis metric {{ iface_config.metric }}  {%         endif %} @@ -84,6 +90,11 @@ router isis VyOS {{ 'vrf ' + vrf if vrf is vyos_defined }}  {% if max_lsp_lifetime is vyos_defined %}   max-lsp-lifetime {{ max_lsp_lifetime }}  {% endif %} +{% if ldp_sync.holddown is vyos_defined %} + mpls ldp-sync holddown {{ ldp_sync.holddown }} +{% elif ldp_sync is vyos_defined %} + mpls ldp-sync +{% endif %}  {% if spf_interval is vyos_defined %}   spf-interval {{ spf_interval }}  {% endif %} diff --git a/data/templates/frr/ospfd.frr.j2 b/data/templates/frr/ospfd.frr.j2 index 8c4a81c57..3f97b7325 100644 --- a/data/templates/frr/ospfd.frr.j2 +++ b/data/templates/frr/ospfd.frr.j2 @@ -44,6 +44,12 @@ interface {{ iface }}  {%         if iface_config.bfd.profile is vyos_defined %}   ip ospf bfd profile {{ iface_config.bfd.profile }}  {%         endif %} +{%         if iface_config.ldp_sync.disable is vyos_defined %} + no ip ospf mpls ldp-sync +{%         elif iface_config.ldp_sync.holddown is vyos_defined %} + ip ospf mpls ldp-sync + ip ospf mpls ldp-sync holddown {{ iface_config.ldp_sync.holddown }} +{%         endif %}  {%         if iface_config.mtu_ignore is vyos_defined %}   ip ospf mtu-ignore  {%         endif %} @@ -133,6 +139,11 @@ router ospf {{ 'vrf ' ~ vrf if vrf is vyos_defined }}  {% if maximum_paths is vyos_defined %}   maximum-paths {{ maximum_paths }}  {% endif %} +{% if ldp_sync.holddown is vyos_defined %} + mpls ldp-sync holddown {{ ldp_sync.holddown }} +{% elif ldp_sync is vyos_defined %} + mpls ldp-sync +{% endif %}  {% if distance.global is vyos_defined %}   distance {{ distance.global }}  {% endif %} diff --git a/data/templates/frr/vrf-vni.frr.j2 b/data/templates/frr/vrf-vni.frr.j2 deleted file mode 100644 index e5f4810a1..000000000 --- a/data/templates/frr/vrf-vni.frr.j2 +++ /dev/null @@ -1,9 +0,0 @@ -{% if name is vyos_defined %} -{%     for vrf, vrf_config in name.items() %} -vrf {{ vrf }} -{%         if vrf_config.vni is vyos_defined %} - vni {{ vrf_config.vni }} -{%         endif %} - exit-vrf -{%     endfor %} -{% endif %} diff --git a/data/templates/frr/vrf.route-map.frr.j2 b/data/templates/frr/vrf.route-map.frr.j2 deleted file mode 100644 index 5e0c56a7b..000000000 --- a/data/templates/frr/vrf.route-map.frr.j2 +++ /dev/null @@ -1,10 +0,0 @@ -! -{% if vrf is vyos_defined and route_map is vyos_defined %} -vrf {{ vrf }} - ip protocol {{ protocol }} route-map {{ route_map }} - exit-vrf -! -{% elif route_map is vyos_defined %} -ip protocol {{ protocol }} route-map {{ route_map }} -{% endif %} -! diff --git a/data/templates/frr/vrf.route-map.v6.frr.j2 b/data/templates/frr/vrf.route-map.v6.frr.j2 deleted file mode 100644 index 7dc59a046..000000000 --- a/data/templates/frr/vrf.route-map.v6.frr.j2 +++ /dev/null @@ -1,10 +0,0 @@ -! -{% if vrf is vyos_defined and route_map is vyos_defined %} -vrf {{ vrf }} - ipv6 protocol {{ protocol }} route-map {{ route_map }} - exit-vrf -! -{% elif route_map is vyos_defined %} -ipv6 protocol {{ protocol }} route-map {{ route_map }} -{% endif %} -! diff --git a/data/templates/frr/zebra.route-map.frr.j2 b/data/templates/frr/zebra.route-map.frr.j2 new file mode 100644 index 000000000..8e18abbde --- /dev/null +++ b/data/templates/frr/zebra.route-map.frr.j2 @@ -0,0 +1,9 @@ +! +{% if protocol is vyos_defined %} +{%     for protocol_name, protocol_config in protocol.items() %} +{%         if protocol_name is vyos_defined('ospfv3') %} +{%             set protocol_name = 'ospf6' %} +{%         endif %} +{{ afi }} protocol {{ protocol_name }} route-map {{ protocol_config.route_map }} +{%     endfor %} +{% endif %} diff --git a/data/templates/frr/zebra.vrf.route-map.frr.j2 b/data/templates/frr/zebra.vrf.route-map.frr.j2 new file mode 100644 index 000000000..eb6abd8e7 --- /dev/null +++ b/data/templates/frr/zebra.vrf.route-map.frr.j2 @@ -0,0 +1,24 @@ +! +{% if name is vyos_defined %} +{%     for vrf, vrf_config in name.items() %} +vrf {{ vrf }} +{%         if vrf_config.ip.protocol is vyos_defined %} +{%             for protocol_name, protocol_config in vrf_config.ip.protocol.items() %} + ip protocol {{ protocol_name }} route-map {{ protocol_config.route_map }} +{%             endfor %} +{%         endif %} +{%         if vrf_config.ipv6.protocol is vyos_defined %} +{%             for protocol_name, protocol_config in vrf_config.ipv6.protocol.items() %} +{%                 if protocol_name is vyos_defined('ospfv3') %} +{%                     set protocol_name = 'ospf6' %} +{%                 endif %} + ipv6 protocol {{ protocol_name }} route-map {{ protocol_config.route_map }} +{%             endfor %} +{%         endif %} +{%         if vrf_config.vni is vyos_defined %} + vni {{ vrf_config.vni }} +{%         endif %} +{%     endfor %} + exit-vrf +! +{% endif %} diff --git a/data/templates/https/nginx.default.j2 b/data/templates/https/nginx.default.j2 index d42b3b389..b541ff309 100644 --- a/data/templates/https/nginx.default.j2 +++ b/data/templates/https/nginx.default.j2 @@ -50,6 +50,12 @@ server {  {%     else %}                  return 503;  {%     endif %} +{%     if server.allow_client %} +{%         for client in server.allow_client %} +                allow {{ client }}; +{%         endfor %} +                deny all; +{%     endif %}          }          error_page 497 =301 https://$host:{{ server.port }}$request_uri; diff --git a/data/templates/login/limits.j2 b/data/templates/login/limits.j2 new file mode 100644 index 000000000..5e2c11f35 --- /dev/null +++ b/data/templates/login/limits.j2 @@ -0,0 +1,5 @@ +# Generated by /usr/libexec/vyos/conf_mode/system-login.py + +{% if max_login_session is vyos_defined %} +* - maxsyslogins {{ max_login_session }} +{% endif %} diff --git a/data/templates/sflow/hsflowd.conf.j2 b/data/templates/sflow/hsflowd.conf.j2 index 94f5939be..5000956bd 100644 --- a/data/templates/sflow/hsflowd.conf.j2 +++ b/data/templates/sflow/hsflowd.conf.j2 @@ -28,4 +28,5 @@ sflow {  {% if drop_monitor_limit is vyos_defined %}    dropmon { limit={{ drop_monitor_limit }} start=on sw=on hw=off }  {% endif %} +  dbus { }  } diff --git a/data/templates/telegraf/telegraf.j2 b/data/templates/telegraf/telegraf.j2 index c9f402281..5852d6232 100644 --- a/data/templates/telegraf/telegraf.j2 +++ b/data/templates/telegraf/telegraf.j2 @@ -12,7 +12,7 @@    debug = false    quiet = false    logfile = "" -  hostname = "" +  hostname = "{{ hostname }}"    omit_hostname = false  {% if azure_data_explorer is vyos_defined %}  ### Azure Data Explorer ### diff --git a/debian/control b/debian/control index 028b7cd43..3126e6ad9 100644 --- a/debian/control +++ b/debian/control @@ -34,7 +34,9 @@ Package: vyos-1x  Architecture: amd64 arm64  Depends:    ${python3:Depends}, +  aardvark-dns,    accel-ppp, +  auditd,    avahi-daemon,    beep,    bmon, @@ -80,6 +82,7 @@ Depends:    lcdproc,    lcdproc-extra-drivers,    libatomic1, +  libauparse0,    libbpf1 [amd64],    libcharon-extra-plugins (>=5.9),    libcharon-extauth-plugins (>=5.9), @@ -99,6 +102,7 @@ Depends:    mtr-tiny,    ndisc6,    ndppd, +  netavark,    netplug,    nfct,    nftables (>= 0.9.3), diff --git a/interface-definitions/bcast-relay.xml.in b/interface-definitions/bcast-relay.xml.in index aeaa5ab37..e2993f3f3 100644 --- a/interface-definitions/bcast-relay.xml.in +++ b/interface-definitions/bcast-relay.xml.in @@ -34,11 +34,7 @@                    </constraint>                  </properties>                </leafNode> -              <leafNode name="description"> -                <properties> -                  <help>Description</help> -                </properties> -              </leafNode> +              #include <include/generic-description.xml.i>                #include <include/generic-interface-multi.xml.i>                #include <include/port-number.xml.i>              </children> diff --git a/interface-definitions/container.xml.in b/interface-definitions/container.xml.in index 6947ed500..9b6d2369d 100644 --- a/interface-definitions/container.xml.in +++ b/interface-definitions/container.xml.in @@ -117,7 +117,7 @@              <properties>                <help>Container host name</help>                <constraint> -                #include <include/constraint/host-name.xml.in> +                #include <include/constraint/host-name.xml.i>                </constraint>                <constraintErrorMessage>Host-name must be alphanumeric and can contain hyphens</constraintErrorMessage>              </properties> @@ -191,15 +191,20 @@              <children>                <leafNode name="address">                  <properties> -                  <!-- PODMAN currently does not support more then one IPv4 or IPv6 address assignments to a container -->                    <help>Assign static IP address to container</help>                    <valueHelp>                      <format>ipv4</format>                      <description>IPv4 address</description>                    </valueHelp> +                  <valueHelp> +                    <format>ipv6</format> +                    <description>IPv6 address</description> +                  </valueHelp>                    <constraint>                      <validator name="ipv4-address"/> +                    <validator name="ipv6-address"/>                    </constraint> +                  <multi/>                  </properties>                </leafNode>              </children> @@ -343,11 +348,7 @@            <constraintErrorMessage>Network name cannot be longer than 11 characters</constraintErrorMessage>          </properties>          <children> -          <leafNode name="description"> -            <properties> -              <help>Network description</help> -            </properties> -          </leafNode> +          #include <include/generic-description.xml.i>            <leafNode name="prefix">              <properties>                <help>Prefix which allocated to that network</help> @@ -366,6 +367,7 @@                <multi/>              </properties>            </leafNode> +          #include <include/interface/vrf.xml.i>          </children>        </tagNode>        <tagNode name="registry"> diff --git a/interface-definitions/dhcp-relay.xml.in b/interface-definitions/dhcp-relay.xml.in index 79ad2c01c..2a2597dd5 100644 --- a/interface-definitions/dhcp-relay.xml.in +++ b/interface-definitions/dhcp-relay.xml.in @@ -21,7 +21,7 @@                  <description>Interface name</description>                </valueHelp>                <constraint> -                #include <include/constraint/interface-name.xml.in> +                #include <include/constraint/interface-name.xml.i>                </constraint>                <multi/>              </properties> @@ -37,7 +37,7 @@                  <description>Interface name</description>                </valueHelp>                <constraint> -                #include <include/constraint/interface-name.xml.in> +                #include <include/constraint/interface-name.xml.i>                </constraint>                <multi/>              </properties> diff --git a/interface-definitions/dns-domain-name.xml.in b/interface-definitions/dns-domain-name.xml.in index c0ac16a80..e93c49ebd 100644 --- a/interface-definitions/dns-domain-name.xml.in +++ b/interface-definitions/dns-domain-name.xml.in @@ -25,7 +25,7 @@            <constraint>              <validator name="ipv4-address"/>              <validator name="ipv6-address"/> -            #include <include/constraint/interface-name.xml.in> +            #include <include/constraint/interface-name.xml.i>            </constraint>          </properties>        </leafNode> @@ -34,7 +34,7 @@          <properties>            <help>System host name (default: vyos)</help>            <constraint> -            #include <include/constraint/host-name.xml.in> +            #include <include/constraint/host-name.xml.i>            </constraint>          </properties>        </leafNode> diff --git a/interface-definitions/dns-forwarding.xml.in b/interface-definitions/dns-forwarding.xml.in index 14b38b24d..6b7344b1d 100644 --- a/interface-definitions/dns-forwarding.xml.in +++ b/interface-definitions/dns-forwarding.xml.in @@ -83,6 +83,13 @@                <tagNode name="domain">                  <properties>                    <help>Domain to forward to a custom DNS server</help> +                  <valueHelp> +                    <format>txt</format> +                    <description>An absolute DNS domain name</description> +                  </valueHelp> +                  <constraint> +                    <validator name="fqdn"/> +                  </constraint>                  </properties>                  <children>                    #include <include/name-server-ipv4-ipv6-port.xml.i> @@ -104,11 +111,11 @@                  <properties>                    <help>Domain to host authoritative records for</help>                    <valueHelp> -                    <format>text</format> -                    <description>An absolute DNS name</description> +                    <format>txt</format> +                    <description>An absolute DNS domain name</description>                    </valueHelp>                    <constraint> -                    <regex>[-_a-zA-Z0-9.]{1,63}</regex> +                    <validator name="fqdn"/>                    </constraint>                  </properties>                  <children> @@ -121,7 +128,7 @@                          <properties>                            <help>"A" record</help>                            <valueHelp> -                            <format>text</format> +                            <format>txt</format>                              <description>A DNS name relative to the root record</description>                            </valueHelp>                            <valueHelp> @@ -158,7 +165,7 @@                          <properties>                            <help>"AAAA" record</help>                            <valueHelp> -                            <format>text</format> +                            <format>txt</format>                              <description>A DNS name relative to the root record</description>                            </valueHelp>                            <valueHelp> @@ -195,7 +202,7 @@                          <properties>                            <help>"CNAME" record</help>                            <valueHelp> -                            <format>text</format> +                            <format>txt</format>                              <description>A DNS name relative to the root record</description>                            </valueHelp>                            <valueHelp> @@ -227,7 +234,7 @@                          <properties>                            <help>"MX" record</help>                            <valueHelp> -                            <format>text</format> +                            <format>txt</format>                              <description>A DNS name relative to the root record</description>                            </valueHelp>                            <valueHelp> @@ -274,7 +281,7 @@                          <properties>                            <help>"PTR" record</help>                            <valueHelp> -                            <format>text</format> +                            <format>txt</format>                              <description>A DNS name relative to the root record</description>                            </valueHelp>                            <valueHelp> @@ -306,7 +313,7 @@                          <properties>                            <help>"TXT" record</help>                            <valueHelp> -                            <format>text</format> +                            <format>txt</format>                              <description>A DNS name relative to the root record</description>                            </valueHelp>                            <valueHelp> @@ -322,7 +329,7 @@                              <properties>                                <help>Record contents</help>                                <valueHelp> -                                <format>text</format> +                                <format>txt</format>                                  <description>Record contents</description>                                </valueHelp>                                <multi/> @@ -336,7 +343,7 @@                          <properties>                            <help>"SPF" record (type=SPF)</help>                            <valueHelp> -                            <format>text</format> +                            <format>txt</format>                              <description>A DNS name relative to the root record</description>                            </valueHelp>                            <valueHelp> @@ -352,7 +359,7 @@                              <properties>                                <help>Record contents</help>                                <valueHelp> -                                <format>text</format> +                                <format>txt</format>                                  <description>Record contents</description>                                </valueHelp>                              </properties> @@ -365,7 +372,7 @@                          <properties>                            <help>"SRV" record</help>                            <valueHelp> -                            <format>text</format> +                            <format>txt</format>                              <description>A DNS name relative to the root record</description>                            </valueHelp>                            <valueHelp> @@ -449,7 +456,7 @@                          <properties>                            <help>"NAPTR" record</help>                            <valueHelp> -                            <format>text</format> +                            <format>txt</format>                              <description>A DNS name relative to the root record</description>                            </valueHelp>                            <valueHelp> diff --git a/interface-definitions/firewall.xml.in b/interface-definitions/firewall.xml.in index 624d61759..69901e5d3 100644 --- a/interface-definitions/firewall.xml.in +++ b/interface-definitions/firewall.xml.in @@ -349,6 +349,9 @@            <completionHelp>              <script>${vyos_completion_dir}/list_interfaces</script>            </completionHelp> +          <constraint> +            #include <include/constraint/interface-name-with-wildcard.xml.i> +          </constraint>          </properties>          <children>            <node name="in"> diff --git a/interface-definitions/high-availability.xml.in b/interface-definitions/high-availability.xml.in index 1fa051df9..ce6603796 100644 --- a/interface-definitions/high-availability.xml.in +++ b/interface-definitions/high-availability.xml.in @@ -220,7 +220,7 @@                          <description>Interface name</description>                        </valueHelp>                        <constraint> -                        #include <include/constraint/interface-name.xml.in> +                        #include <include/constraint/interface-name.xml.i>                        </constraint>                        <multi/>                      </properties> diff --git a/interface-definitions/https.xml.in b/interface-definitions/https.xml.in index 6adb07598..cf30ab2be 100644 --- a/interface-definitions/https.xml.in +++ b/interface-definitions/https.xml.in @@ -60,6 +60,7 @@                    <multi/>                  </properties>                </leafNode> +              #include <include/allow-client.xml.i>              </children>            </tagNode>            <node name="api" owner="${vyos_conf_scripts_dir}/http-api.py"> diff --git a/interface-definitions/include/allow-client.xml.i b/interface-definitions/include/allow-client.xml.i new file mode 100644 index 000000000..1b06e2c17 --- /dev/null +++ b/interface-definitions/include/allow-client.xml.i @@ -0,0 +1,35 @@ +<!-- include start from allow-client.xml.i --> +<node name="allow-client"> +  <properties> +    <help>Restrict to allowed IP client addresses</help> +  </properties> +  <children> +    <leafNode name="address"> +      <properties> +        <help>Allowed IP client addresses</help> +        <valueHelp> +          <format>ipv4</format> +          <description>IPv4 address</description> +        </valueHelp> +        <valueHelp> +          <format>ipv6</format> +          <description>IPv6 address</description> +        </valueHelp> +        <valueHelp> +          <format>ipv4net</format> +          <description>IPv4 address and prefix length</description> +        </valueHelp> +        <valueHelp> +          <format>ipv6net</format> +          <description>IPv6 address and prefix length</description> +        </valueHelp> +        <constraint> +          <validator name="ip-address"/> +          <validator name="ip-cidr"/> +        </constraint> +        <multi/> +      </properties> +    </leafNode> +  </children> +</node> +<!-- include end --> diff --git a/interface-definitions/include/babel/interface.xml.i b/interface-definitions/include/babel/interface.xml.i index 586eca7a5..a122ef024 100644 --- a/interface-definitions/include/babel/interface.xml.i +++ b/interface-definitions/include/babel/interface.xml.i @@ -10,7 +10,7 @@        <description>Interface name</description>      </valueHelp>      <constraint> -      #include <include/constraint/interface-name.xml.in> +      #include <include/constraint/interface-name.xml.i>      </constraint>    </properties>    <children> diff --git a/interface-definitions/include/bgp/afi-ipv4-prefix-list.xml.i b/interface-definitions/include/bgp/afi-ipv4-prefix-list.xml.i index ee902b0b6..0f760daae 100644 --- a/interface-definitions/include/bgp/afi-ipv4-prefix-list.xml.i +++ b/interface-definitions/include/bgp/afi-ipv4-prefix-list.xml.i @@ -15,7 +15,7 @@            <description>Name of IPv4 prefix-list</description>          </valueHelp>          <constraint> -          #include <include/constraint/alpha-numeric-hyphen-underscore.xml.in> +          #include <include/constraint/alpha-numeric-hyphen-underscore.xml.i>          </constraint>          <constraintErrorMessage>Name of prefix-list can only contain alpha-numeric letters, hyphen and underscores</constraintErrorMessage>        </properties> @@ -31,7 +31,7 @@            <description>Name of IPv4 prefix-list</description>          </valueHelp>          <constraint> -          #include <include/constraint/alpha-numeric-hyphen-underscore.xml.in> +          #include <include/constraint/alpha-numeric-hyphen-underscore.xml.i>          </constraint>          <constraintErrorMessage>Name of prefix-list can only contain alpha-numeric letters, hyphen and underscores</constraintErrorMessage>        </properties> diff --git a/interface-definitions/include/bgp/afi-ipv6-prefix-list.xml.i b/interface-definitions/include/bgp/afi-ipv6-prefix-list.xml.i index da966f193..268d9cbc0 100644 --- a/interface-definitions/include/bgp/afi-ipv6-prefix-list.xml.i +++ b/interface-definitions/include/bgp/afi-ipv6-prefix-list.xml.i @@ -15,7 +15,7 @@            <description>Name of IPv6 prefix-list</description>          </valueHelp>          <constraint> -          #include <include/constraint/alpha-numeric-hyphen-underscore.xml.in> +          #include <include/constraint/alpha-numeric-hyphen-underscore.xml.i>          </constraint>          <constraintErrorMessage>Name of prefix-list6 can only contain alpha-numeric letters, hyphen and underscores</constraintErrorMessage>        </properties> @@ -31,7 +31,7 @@            <description>Name of IPv6 prefix-list</description>          </valueHelp>          <constraint> -          #include <include/constraint/alpha-numeric-hyphen-underscore.xml.in> +          #include <include/constraint/alpha-numeric-hyphen-underscore.xml.i>          </constraint>          <constraintErrorMessage>Name of prefix-list6 can only contain alpha-numeric letters, hyphen and underscores</constraintErrorMessage>        </properties> diff --git a/interface-definitions/include/bgp/neighbor-update-source.xml.i b/interface-definitions/include/bgp/neighbor-update-source.xml.i index 0acec4126..c6aa776c2 100644 --- a/interface-definitions/include/bgp/neighbor-update-source.xml.i +++ b/interface-definitions/include/bgp/neighbor-update-source.xml.i @@ -22,7 +22,7 @@      <constraint>        <validator name="ipv4-address"/>        <validator name="ipv6-address"/> -      #include <include/constraint/interface-name.xml.in> +      #include <include/constraint/interface-name.xml.i>      </constraint>    </properties>  </leafNode> diff --git a/interface-definitions/include/bgp/protocol-common-config.xml.i b/interface-definitions/include/bgp/protocol-common-config.xml.i index 089c36ef3..bcc131f83 100644 --- a/interface-definitions/include/bgp/protocol-common-config.xml.i +++ b/interface-definitions/include/bgp/protocol-common-config.xml.i @@ -810,12 +810,6 @@              </node>            </children>          </node> -        <leafNode name="advertise-all-vni"> -          <properties> -            <help>Advertise All local VNIs</help> -            <valueless/> -          </properties> -        </leafNode>          #include <include/bgp/afi-l2vpn-common.xml.i>          <leafNode name="advertise-pip">            <properties> @@ -942,7 +936,7 @@      <constraint>        <validator name="ipv4-address"/>        <validator name="ipv6-address"/> -      #include <include/constraint/interface-name.xml.in> +      #include <include/constraint/interface-name.xml.i>      </constraint>    </properties>    <children> @@ -1530,7 +1524,7 @@    <properties>      <help>Name of peer-group</help>      <constraint> -      #include <include/constraint/alpha-numeric-hyphen-underscore.xml.in> +      #include <include/constraint/alpha-numeric-hyphen-underscore.xml.i>      </constraint>    </properties>    <children> @@ -1565,7 +1559,6 @@      #include <include/port-number.xml.i>    </children>  </tagNode> -#include <include/route-map.xml.i>  <node name="timers">    <properties>      <help>BGP protocol timers</help> diff --git a/interface-definitions/include/constraint/alpha-numeric-hyphen-underscore.xml.in b/interface-definitions/include/constraint/alpha-numeric-hyphen-underscore.xml.i index eb568d7d9..eb568d7d9 100644 --- a/interface-definitions/include/constraint/alpha-numeric-hyphen-underscore.xml.in +++ b/interface-definitions/include/constraint/alpha-numeric-hyphen-underscore.xml.i diff --git a/interface-definitions/include/constraint/host-name.xml.in b/interface-definitions/include/constraint/host-name.xml.i index 202c200f4..202c200f4 100644 --- a/interface-definitions/include/constraint/host-name.xml.in +++ b/interface-definitions/include/constraint/host-name.xml.i diff --git a/interface-definitions/include/constraint/interface-name-with-wildcard.xml.i b/interface-definitions/include/constraint/interface-name-with-wildcard.xml.i new file mode 100644 index 000000000..09867b380 --- /dev/null +++ b/interface-definitions/include/constraint/interface-name-with-wildcard.xml.i @@ -0,0 +1,4 @@ +<!-- include start from constraint/interface-name-with-wildcard.xml.in --> +<regex>(bond|br|dum|en|ersp|eth|gnv|ifb|lan|l2tp|l2tpeth|macsec|peth|ppp|pppoe|pptp|sstp|tun|veth|vti|vtun|vxlan|wg|wlan|wwan)([0-9]?)(\*?)(.+)?|lo</regex> +<validator name="file-path --lookup-path /sys/class/net --directory"/> +<!-- include end --> diff --git a/interface-definitions/include/constraint/interface-name.xml.in b/interface-definitions/include/constraint/interface-name.xml.i index e540e4418..e540e4418 100644 --- a/interface-definitions/include/constraint/interface-name.xml.in +++ b/interface-definitions/include/constraint/interface-name.xml.i diff --git a/interface-definitions/include/dhcp-interface-multi.xml.i b/interface-definitions/include/dhcp-interface-multi.xml.i index e10341037..0db11cf79 100644 --- a/interface-definitions/include/dhcp-interface-multi.xml.i +++ b/interface-definitions/include/dhcp-interface-multi.xml.i @@ -10,7 +10,7 @@        <description>DHCP interface name</description>      </valueHelp>      <constraint> -      #include <include/constraint/interface-name.xml.in> +      #include <include/constraint/interface-name.xml.i>      </constraint>      <multi/>    </properties> diff --git a/interface-definitions/include/dhcp-interface.xml.i b/interface-definitions/include/dhcp-interface.xml.i index 24edbbd15..b5c94cb24 100644 --- a/interface-definitions/include/dhcp-interface.xml.i +++ b/interface-definitions/include/dhcp-interface.xml.i @@ -9,7 +9,7 @@            <description>DHCP interface name</description>          </valueHelp>          <constraint> -          #include <include/constraint/interface-name.xml.in> +          #include <include/constraint/interface-name.xml.i>          </constraint>        </properties>      </leafNode> diff --git a/interface-definitions/include/eigrp/protocol-common-config.xml.i b/interface-definitions/include/eigrp/protocol-common-config.xml.i index 88365187a..a21d18424 100644 --- a/interface-definitions/include/eigrp/protocol-common-config.xml.i +++ b/interface-definitions/include/eigrp/protocol-common-config.xml.i @@ -107,7 +107,6 @@      <multi/>    </properties>  </leafNode> -#include <include/route-map.xml.i>  #include <include/router-id.xml.i>  <!-- FRR timers not implemented yet -->  <leafNode name="variance"> diff --git a/interface-definitions/include/generic-interface-broadcast.xml.i b/interface-definitions/include/generic-interface-broadcast.xml.i index 82bfc139b..e37e75012 100644 --- a/interface-definitions/include/generic-interface-broadcast.xml.i +++ b/interface-definitions/include/generic-interface-broadcast.xml.i @@ -1,7 +1,7 @@  <!-- include start from generic-interface-broadcast.xml.i -->  <leafNode name="interface">    <properties> -    <help>Interface Name to use</help> +    <help>Interface to use</help>      <completionHelp>        <script>${vyos_completion_dir}/list_interfaces --broadcast</script>      </completionHelp> @@ -10,7 +10,7 @@        <description>Interface name</description>      </valueHelp>      <constraint> -      #include <include/constraint/interface-name.xml.in> +      #include <include/constraint/interface-name.xml.i>      </constraint>    </properties>  </leafNode> diff --git a/interface-definitions/include/generic-interface-multi-broadcast.xml.i b/interface-definitions/include/generic-interface-multi-broadcast.xml.i index 8160f816d..ed13cf2cf 100644 --- a/interface-definitions/include/generic-interface-multi-broadcast.xml.i +++ b/interface-definitions/include/generic-interface-multi-broadcast.xml.i @@ -1,7 +1,7 @@  <!-- include start from generic-interface-multi-broadcast.xml.i -->  <leafNode name="interface">    <properties> -    <help>Interface Name to use</help> +    <help>Interface to use</help>      <completionHelp>        <script>${vyos_completion_dir}/list_interfaces --broadcast</script>      </completionHelp> @@ -10,7 +10,7 @@        <description>Interface name</description>      </valueHelp>      <constraint> -      #include <include/constraint/interface-name.xml.in> +      #include <include/constraint/interface-name.xml.i>      </constraint>      <multi/>    </properties> diff --git a/interface-definitions/include/generic-interface-multi-wildcard.xml.i b/interface-definitions/include/generic-interface-multi-wildcard.xml.i new file mode 100644 index 000000000..6c846a795 --- /dev/null +++ b/interface-definitions/include/generic-interface-multi-wildcard.xml.i @@ -0,0 +1,18 @@ +<!-- include start from generic-interface-multi-wildcard.xml.i --> +<leafNode name="interface"> +  <properties> +    <help>Interface to use</help> +    <completionHelp> +      <script>${vyos_completion_dir}/list_interfaces</script> +    </completionHelp> +    <valueHelp> +      <format>txt</format> +      <description>Interface name, wildcard (*) supported</description> +    </valueHelp> +    <constraint> +      #include <include/constraint/interface-name-with-wildcard.xml.i> +    </constraint> +    <multi/> +  </properties> +</leafNode> +<!-- include end --> diff --git a/interface-definitions/include/generic-interface-multi.xml.i b/interface-definitions/include/generic-interface-multi.xml.i index 1b8dc102b..cfc77af3a 100644 --- a/interface-definitions/include/generic-interface-multi.xml.i +++ b/interface-definitions/include/generic-interface-multi.xml.i @@ -10,7 +10,7 @@        <description>Interface name</description>      </valueHelp>      <constraint> -      #include <include/constraint/interface-name.xml.in> +      #include <include/constraint/interface-name.xml.i>      </constraint>      <multi/>    </properties> diff --git a/interface-definitions/include/generic-interface.xml.i b/interface-definitions/include/generic-interface.xml.i index 9417f9ef0..65f5bfbb8 100644 --- a/interface-definitions/include/generic-interface.xml.i +++ b/interface-definitions/include/generic-interface.xml.i @@ -10,7 +10,7 @@        <description>Interface name</description>      </valueHelp>      <constraint> -      #include <include/constraint/interface-name.xml.in> +      #include <include/constraint/interface-name.xml.i>      </constraint>    </properties>  </leafNode> diff --git a/interface-definitions/include/interface/redirect.xml.i b/interface-definitions/include/interface/redirect.xml.i index 0421f4074..9b41cd8ff 100644 --- a/interface-definitions/include/interface/redirect.xml.i +++ b/interface-definitions/include/interface/redirect.xml.i @@ -10,7 +10,7 @@        <description>Destination interface name</description>      </valueHelp>      <constraint> -      #include <include/constraint/interface-name.xml.in> +      #include <include/constraint/interface-name.xml.i>      </constraint>    </properties>  </leafNode> diff --git a/interface-definitions/include/isis/ldp-sync-holddown.xml.i b/interface-definitions/include/isis/ldp-sync-holddown.xml.i new file mode 100644 index 000000000..15ac26f07 --- /dev/null +++ b/interface-definitions/include/isis/ldp-sync-holddown.xml.i @@ -0,0 +1,14 @@ +<!-- include start from isis/ldp-sync-holddown.xml.i --> +<leafNode name="holddown"> +  <properties> +    <help>Hold down timer for LDP-IGP cost restoration</help> +    <valueHelp> +      <format>u32:0-10000</format> +      <description>Time to wait in seconds for LDP-IGP synchronization to occur before restoring interface cost</description> +    </valueHelp> +    <constraint> +      <validator name="numeric" argument="--range 0-10000"/> +    </constraint> +  </properties> +</leafNode> +<!-- include end --> diff --git a/interface-definitions/include/isis/ldp-sync-interface.xml.i b/interface-definitions/include/isis/ldp-sync-interface.xml.i new file mode 100644 index 000000000..222a35256 --- /dev/null +++ b/interface-definitions/include/isis/ldp-sync-interface.xml.i @@ -0,0 +1,11 @@ +<!-- include start from isis/ldp-igp-sync.xml.i --> +<node name="ldp-sync"> +  <properties> +    <help>LDP-IGP synchronization configuration for interface</help> +  </properties> +  <children> +    #include <include/generic-disable-node.xml.i> +    #include <include/isis/ldp-sync-holddown.xml.i> +  </children> +</node> +<!-- include end --> diff --git a/interface-definitions/include/isis/ldp-sync-protocol.xml.i b/interface-definitions/include/isis/ldp-sync-protocol.xml.i new file mode 100644 index 000000000..b2e696a70 --- /dev/null +++ b/interface-definitions/include/isis/ldp-sync-protocol.xml.i @@ -0,0 +1,10 @@ +<!-- include start from isis/ldp-igp-sync.xml.i --> +<node name="ldp-sync"> +  <properties> +    <help>Protocol wide LDP-IGP synchronization configuration</help> +  </properties> +  <children> +    #include <include/isis/ldp-sync-holddown.xml.i> +  </children> +</node> +<!-- include end --> diff --git a/interface-definitions/include/isis/protocol-common-config.xml.i b/interface-definitions/include/isis/protocol-common-config.xml.i index 0e6f19480..4ca7061db 100644 --- a/interface-definitions/include/isis/protocol-common-config.xml.i +++ b/interface-definitions/include/isis/protocol-common-config.xml.i @@ -152,6 +152,7 @@      </constraint>    </properties>  </leafNode> +#include <include/isis/ldp-sync-protocol.xml.i>  <leafNode name="net">    <properties>      <help>A Network Entity Title for this process (ISO only)</help> @@ -172,7 +173,7 @@  </leafNode>  <node name="traffic-engineering">    <properties> -    <help>Show IS-IS neighbor adjacencies</help> +    <help>IS-IS traffic engineering extensions</help>    </properties>    <children>      <leafNode name="enable"> @@ -631,6 +632,7 @@        </properties>      </leafNode>      #include <include/isis/metric.xml.i> +    #include <include/isis/ldp-sync-interface.xml.i>      <node name="network">        <properties>          <help>Set network type</help> @@ -685,5 +687,4 @@      </leafNode>    </children>  </tagNode> -#include <include/route-map.xml.i>  <!-- include end --> diff --git a/interface-definitions/include/ospf/protocol-common-config.xml.i b/interface-definitions/include/ospf/protocol-common-config.xml.i index 25b54b181..b7f22cb88 100644 --- a/interface-definitions/include/ospf/protocol-common-config.xml.i +++ b/interface-definitions/include/ospf/protocol-common-config.xml.i @@ -331,6 +331,7 @@      </constraint>    </properties>  </leafNode> +#include <include/isis/ldp-sync-protocol.xml.i>  <node name="distance">    <properties>      <help>Administrative distance</help> @@ -358,7 +359,7 @@        <description>Interface name</description>      </valueHelp>      <constraint> -      #include <include/constraint/interface-name.xml.in> +      #include <include/constraint/interface-name.xml.i>      </constraint>    </properties>    <children> @@ -385,6 +386,7 @@      #include <include/ospf/authentication.xml.i>      #include <include/ospf/intervals.xml.i>      #include <include/ospf/interface-common.xml.i> +    #include <include/isis/ldp-sync-interface.xml.i>      <leafNode name="bandwidth">        <properties>          <help>Interface bandwidth (Mbit/s)</help> @@ -814,7 +816,6 @@      </leafNode>    </children>  </node> -#include <include/route-map.xml.i>  <node name="timers">    <properties>      <help>Adjust routing timers</help> @@ -875,4 +876,4 @@      </node>    </children>  </node> -<!-- include end --> +<!-- include end -->
\ No newline at end of file diff --git a/interface-definitions/include/ospfv3/protocol-common-config.xml.i b/interface-definitions/include/ospfv3/protocol-common-config.xml.i index 014bf9e49..a7de50638 100644 --- a/interface-definitions/include/ospfv3/protocol-common-config.xml.i +++ b/interface-definitions/include/ospfv3/protocol-common-config.xml.i @@ -118,7 +118,7 @@        <description>Interface used for routing information exchange</description>      </valueHelp>      <constraint> -      #include <include/constraint/interface-name.xml.in> +      #include <include/constraint/interface-name.xml.i>      </constraint>    </properties>    <children> @@ -256,5 +256,4 @@      </node>    </children>  </node> -#include <include/route-map.xml.i>  <!-- include end --> diff --git a/interface-definitions/include/rip/interface.xml.i b/interface-definitions/include/rip/interface.xml.i index 0a89f4d92..8007f0208 100644 --- a/interface-definitions/include/rip/interface.xml.i +++ b/interface-definitions/include/rip/interface.xml.i @@ -10,7 +10,7 @@        <description>Interface name</description>      </valueHelp>      <constraint> -      #include <include/constraint/interface-name.xml.in> +      #include <include/constraint/interface-name.xml.i>      </constraint>    </properties>    <children> diff --git a/interface-definitions/include/routing-passive-interface.xml.i b/interface-definitions/include/routing-passive-interface.xml.i index 715468e59..8fa0d0fe7 100644 --- a/interface-definitions/include/routing-passive-interface.xml.i +++ b/interface-definitions/include/routing-passive-interface.xml.i @@ -16,7 +16,7 @@      </valueHelp>      <constraint>        <regex>(default)</regex> -      #include <include/constraint/interface-name.xml.in> +      #include <include/constraint/interface-name.xml.i>      </constraint>      <multi/>    </properties> diff --git a/interface-definitions/include/source-interface.xml.i b/interface-definitions/include/source-interface.xml.i index c25a6a6d0..40fdc6c5e 100644 --- a/interface-definitions/include/source-interface.xml.i +++ b/interface-definitions/include/source-interface.xml.i @@ -10,7 +10,7 @@        <script>${vyos_completion_dir}/list_interfaces</script>      </completionHelp>      <constraint> -      #include <include/constraint/interface-name.xml.in> +      #include <include/constraint/interface-name.xml.i>      </constraint>    </properties>  </leafNode> diff --git a/interface-definitions/include/static/static-route-interface.xml.i b/interface-definitions/include/static/static-route-interface.xml.i index db2f0baa6..cb5436847 100644 --- a/interface-definitions/include/static/static-route-interface.xml.i +++ b/interface-definitions/include/static/static-route-interface.xml.i @@ -10,7 +10,7 @@        <description>Gateway interface name</description>      </valueHelp>      <constraint> -      #include <include/constraint/interface-name.xml.in> +      #include <include/constraint/interface-name.xml.i>      </constraint>    </properties>  </leafNode> diff --git a/interface-definitions/include/static/static-route.xml.i b/interface-definitions/include/static/static-route.xml.i index 34e36f5a7..268cfa005 100644 --- a/interface-definitions/include/static/static-route.xml.i +++ b/interface-definitions/include/static/static-route.xml.i @@ -26,7 +26,7 @@            <description>Gateway interface name</description>          </valueHelp>          <constraint> -          #include <include/constraint/interface-name.xml.in> +          #include <include/constraint/interface-name.xml.i>          </constraint>        </properties>        <children> diff --git a/interface-definitions/include/static/static-route6.xml.i b/interface-definitions/include/static/static-route6.xml.i index aac02062f..1f8d54108 100644 --- a/interface-definitions/include/static/static-route6.xml.i +++ b/interface-definitions/include/static/static-route6.xml.i @@ -25,7 +25,7 @@            <description>Gateway interface name</description>          </valueHelp>          <constraint> -          #include <include/constraint/interface-name.xml.in> +          #include <include/constraint/interface-name.xml.i>          </constraint>        </properties>        <children> diff --git a/interface-definitions/include/system-ip-protocol.xml.i b/interface-definitions/include/system-ip-protocol.xml.i new file mode 100644 index 000000000..c630eb3f7 --- /dev/null +++ b/interface-definitions/include/system-ip-protocol.xml.i @@ -0,0 +1,56 @@ +<!-- include start from system-ip-protocol.xml.i --> +<tagNode name="protocol"> +  <properties> +    <help>Filter routing info exchanged between routing protocol and zebra</help> +    <completionHelp> +      <list>any babel bgp connected eigrp isis kernel ospf rip static table</list> +    </completionHelp> +    <valueHelp> +      <format>any</format> +      <description>Any of the above protocols</description> +    </valueHelp> +    <valueHelp> +      <format>babel</format> +      <description>Babel routing protocol</description> +    </valueHelp> +    <valueHelp> +      <format>bgp</format> +      <description>Border Gateway Protocol</description> +    </valueHelp> +    <valueHelp> +      <format>connected</format> +      <description>Connected routes (directly attached subnet or host)</description> +    </valueHelp> +    <valueHelp> +      <format>eigrp</format> +      <description>Enhanced Interior Gateway Routing Protocol</description> +    </valueHelp> +    <valueHelp> +      <format>isis</format> +      <description>Intermediate System to Intermediate System</description> +    </valueHelp> +    <valueHelp> +      <format>kernel</format> +      <description>Kernel routes (not installed via the zebra RIB)</description> +    </valueHelp> +    <valueHelp> +      <format>ospf</format> +      <description>Open Shortest Path First (OSPFv2)</description> +    </valueHelp> +    <valueHelp> +      <format>rip</format> +      <description>Routing Information Protocol</description> +    </valueHelp> +    <valueHelp> +      <format>static</format> +      <description>Statically configured routes</description> +    </valueHelp> +    <constraint> +      <regex>(any|babel|bgp|connected|eigrp|isis|kernel|ospf|rip|static|table)</regex> +    </constraint> +  </properties> +  <children> +    #include <include/route-map.xml.i> +  </children> +</tagNode> +<!-- include end -->
\ No newline at end of file diff --git a/interface-definitions/include/system-ipv6-protocol.xml.i b/interface-definitions/include/system-ipv6-protocol.xml.i new file mode 100644 index 000000000..485776a71 --- /dev/null +++ b/interface-definitions/include/system-ipv6-protocol.xml.i @@ -0,0 +1,52 @@ +<!-- include start from system-ipv6-protocol.xml.i --> +<tagNode name="protocol"> +  <properties> +    <help>Filter routing info exchanged between routing protocol and zebra</help> +    <completionHelp> +      <list>any babel bgp connected isis kernel ospfv3 ripng static table</list> +    </completionHelp> +    <valueHelp> +      <format>any</format> +      <description>Any of the above protocols</description> +    </valueHelp> +    <valueHelp> +      <format>babel</format> +      <description>Babel routing protocol</description> +    </valueHelp> +    <valueHelp> +      <format>bgp</format> +      <description>Border Gateway Protocol</description> +    </valueHelp> +    <valueHelp> +      <format>connected</format> +      <description>Connected routes (directly attached subnet or host)</description> +    </valueHelp> +    <valueHelp> +      <format>isis</format> +      <description>Intermediate System to Intermediate System</description> +    </valueHelp> +    <valueHelp> +      <format>kernel</format> +      <description>Kernel routes (not installed via the zebra RIB)</description> +    </valueHelp> +    <valueHelp> +      <format>ospfv3</format> +      <description>Open Shortest Path First (OSPFv3)</description> +    </valueHelp> +    <valueHelp> +      <format>ripng</format> +      <description>Routing Information Protocol next-generation</description> +    </valueHelp> +    <valueHelp> +      <format>static</format> +      <description>Statically configured routes</description> +    </valueHelp> +    <constraint> +      <regex>(any|babel|bgp|connected|isis|kernel|ospfv3|ripng|static|table)</regex> +    </constraint> +  </properties> +  <children> +    #include <include/route-map.xml.i> +  </children> +</tagNode> +<!-- include end --> diff --git a/interface-definitions/include/version/bgp-version.xml.i b/interface-definitions/include/version/bgp-version.xml.i index ced49e729..1386ea9bc 100644 --- a/interface-definitions/include/version/bgp-version.xml.i +++ b/interface-definitions/include/version/bgp-version.xml.i @@ -1,3 +1,3 @@  <!-- include start from include/version/bgp-version.xml.i --> -<syntaxVersion component='bgp' version='3'></syntaxVersion> +<syntaxVersion component='bgp' version='4'></syntaxVersion>  <!-- include end --> diff --git a/interface-definitions/include/version/isis-version.xml.i b/interface-definitions/include/version/isis-version.xml.i index 7bf12e81a..f50329b09 100644 --- a/interface-definitions/include/version/isis-version.xml.i +++ b/interface-definitions/include/version/isis-version.xml.i @@ -1,3 +1,3 @@  <!-- include start from include/version/isis-version.xml.i --> -<syntaxVersion component='isis' version='2'></syntaxVersion> +<syntaxVersion component='isis' version='3'></syntaxVersion>  <!-- include end --> diff --git a/interface-definitions/include/version/ospf-version.xml.i b/interface-definitions/include/version/ospf-version.xml.i index 755965daa..df108837b 100644 --- a/interface-definitions/include/version/ospf-version.xml.i +++ b/interface-definitions/include/version/ospf-version.xml.i @@ -1,3 +1,3 @@  <!-- include start from include/version/ospf-version.xml.i --> -<syntaxVersion component='ospf' version='1'></syntaxVersion> +<syntaxVersion component='ospf' version='2'></syntaxVersion>  <!-- include end --> diff --git a/interface-definitions/include/version/quagga-version.xml.i b/interface-definitions/include/version/quagga-version.xml.i index f9944acce..23d884cd4 100644 --- a/interface-definitions/include/version/quagga-version.xml.i +++ b/interface-definitions/include/version/quagga-version.xml.i @@ -1,3 +1,3 @@  <!-- include start from include/version/quagga-version.xml.i --> -<syntaxVersion component='quagga' version='10'></syntaxVersion> +<syntaxVersion component='quagga' version='11'></syntaxVersion>  <!-- include end --> diff --git a/interface-definitions/include/version/rip-version.xml.i b/interface-definitions/include/version/rip-version.xml.i new file mode 100644 index 000000000..30ace486a --- /dev/null +++ b/interface-definitions/include/version/rip-version.xml.i @@ -0,0 +1,3 @@ +<!-- include start from include/version/rip-version.xml.i --> +<syntaxVersion component='rip' version='1'></syntaxVersion> +<!-- include end --> diff --git a/interface-definitions/interfaces-bonding.xml.in b/interface-definitions/interfaces-bonding.xml.in index f5f1eb1b6..14b1036b4 100644 --- a/interface-definitions/interfaces-bonding.xml.in +++ b/interface-definitions/interfaces-bonding.xml.in @@ -199,7 +199,7 @@                      <description>Interface name</description>                    </valueHelp>                    <constraint> -                    #include <include/constraint/interface-name.xml.in> +                    #include <include/constraint/interface-name.xml.i>                    </constraint>                    <multi/>                  </properties> @@ -218,7 +218,7 @@                  <description>Interface name</description>                </valueHelp>                <constraint> -                #include <include/constraint/interface-name.xml.in> +                #include <include/constraint/interface-name.xml.i>                </constraint>              </properties>            </leafNode> diff --git a/interface-definitions/load-balancing-wan.xml.in b/interface-definitions/load-balancing-wan.xml.in index 2b812eb4d..c1d7e2c67 100644 --- a/interface-definitions/load-balancing-wan.xml.in +++ b/interface-definitions/load-balancing-wan.xml.in @@ -191,15 +191,7 @@                </constraint>              </properties>              <children> -              <leafNode name="description"> -                <properties> -                  <help>Description for this rule</help> -                  <valueHelp> -                    <format>txt</format> -                    <description>Description for this rule</description> -                  </valueHelp> -                </properties> -              </leafNode> +              #include <include/generic-description.xml.i>                <node name="destination">                  <properties>                    <help>Destination</help> diff --git a/interface-definitions/nat66.xml.in b/interface-definitions/nat66.xml.in index 6ea611789..7a8970bdf 100644 --- a/interface-definitions/nat66.xml.in +++ b/interface-definitions/nat66.xml.in @@ -24,11 +24,7 @@                <constraintErrorMessage>NAT66 rule number must be between 1 and 999999</constraintErrorMessage>              </properties>              <children> -              <leafNode name="description"> -                <properties> -                  <help>Rule description</help> -                </properties> -              </leafNode> +              #include <include/generic-description.xml.i>                <leafNode name="disable">                  <properties>                    <help>Disable NAT66 rule</help> @@ -156,11 +152,7 @@                <constraintErrorMessage>NAT66 rule number must be between 1 and 999999</constraintErrorMessage>              </properties>              <children> -              <leafNode name="description"> -                <properties> -                  <help>Rule description</help> -                </properties> -              </leafNode> +              #include <include/generic-description.xml.i>                <leafNode name="disable">                  <properties>                    <help>Disable NAT66 rule</help> diff --git a/interface-definitions/ntp.xml.in b/interface-definitions/ntp.xml.in index 287401ed6..558204a06 100644 --- a/interface-definitions/ntp.xml.in +++ b/interface-definitions/ntp.xml.in @@ -57,39 +57,7 @@                </leafNode>              </children>            </tagNode> -          <node name="allow-client"> -            <properties> -              <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>Allowed IPv4 prefix</description> -                  </valueHelp> -                  <valueHelp> -                    <format>ipv6</format> -                    <description>Allowed IPv6 address</description> -                  </valueHelp> -                  <valueHelp> -                    <format>ipv6net</format> -                    <description>Allowed IPv6 prefix</description> -                  </valueHelp> -                  <multi/> -                  <constraint> -                    <validator name="ip-address"/> -                    <validator name="ip-prefix"/> -                  </constraint> -                </properties> -              </leafNode> -            </children> -          </node> +          #include <include/allow-client.xml.i>            #include <include/generic-interface-multi.xml.i>            #include <include/listen-address.xml.i>            #include <include/interface/vrf.xml.i> diff --git a/interface-definitions/pki.xml.in b/interface-definitions/pki.xml.in index c4fde2c78..a13a357fd 100644 --- a/interface-definitions/pki.xml.in +++ b/interface-definitions/pki.xml.in @@ -16,11 +16,7 @@                <help>CA certificate in PEM format</help>              </properties>            </leafNode> -          <leafNode name="description"> -            <properties> -              <help>Description</help> -            </properties> -          </leafNode> +          #include <include/generic-description.xml.i>            <node name="private">              <properties>                <help>CA private key in PEM format</help> @@ -63,11 +59,7 @@                <help>Certificate in PEM format</help>              </properties>            </leafNode> -          <leafNode name="description"> -            <properties> -              <help>Description</help> -            </properties> -          </leafNode> +          #include <include/generic-description.xml.i>            <node name="private">              <properties>                <help>Certificate private key</help> diff --git a/interface-definitions/policy-route.xml.in b/interface-definitions/policy-route.xml.in index bbd6dbf56..d4ec75786 100644 --- a/interface-definitions/policy-route.xml.in +++ b/interface-definitions/policy-route.xml.in @@ -12,8 +12,8 @@          </properties>          <children>            #include <include/generic-description.xml.i> -          #include <include/generic-interface-multi.xml.i>            #include <include/firewall/enable-default-log.xml.i> +          #include <include/generic-interface-multi-wildcard.xml.i>            <tagNode name="rule">              <properties>                <help>Policy rule number</help> @@ -67,8 +67,8 @@          </properties>          <children>            #include <include/generic-description.xml.i> -          #include <include/generic-interface-multi.xml.i>            #include <include/firewall/enable-default-log.xml.i> +          #include <include/generic-interface-multi-wildcard.xml.i>            <tagNode name="rule">              <properties>                <help>Policy rule number</help> diff --git a/interface-definitions/policy.xml.in b/interface-definitions/policy.xml.in index 66608be6f..7d5fe79ef 100644 --- a/interface-definitions/policy.xml.in +++ b/interface-definitions/policy.xml.in @@ -242,7 +242,7 @@              <description>BGP extended community-list name</description>            </valueHelp>            <constraint> -            #include <include/constraint/alpha-numeric-hyphen-underscore.xml.in> +            #include <include/constraint/alpha-numeric-hyphen-underscore.xml.i>            </constraint>            <constraintErrorMessage>Should be an alphanumeric name</constraintErrorMessage>          </properties> @@ -291,7 +291,7 @@              <description>BGP large-community-list name</description>            </valueHelp>            <constraint> -            #include <include/constraint/alpha-numeric-hyphen-underscore.xml.in> +            #include <include/constraint/alpha-numeric-hyphen-underscore.xml.i>            </constraint>            <constraintErrorMessage>Should be an alphanumeric name</constraintErrorMessage>          </properties> @@ -340,7 +340,7 @@              <description>Name of IPv4 prefix-list</description>            </valueHelp>            <constraint> -            #include <include/constraint/alpha-numeric-hyphen-underscore.xml.in> +            #include <include/constraint/alpha-numeric-hyphen-underscore.xml.i>            </constraint>            <constraintErrorMessage>Name of prefix-list can only contain alpha-numeric letters, hyphen and underscores</constraintErrorMessage>          </properties> @@ -408,7 +408,7 @@              <description>Name of IPv6 prefix-list</description>            </valueHelp>            <constraint> -            #include <include/constraint/alpha-numeric-hyphen-underscore.xml.in> +            #include <include/constraint/alpha-numeric-hyphen-underscore.xml.i>            </constraint>            <constraintErrorMessage>Name of prefix-list6 can only contain alpha-numeric letters, hyphen and underscores</constraintErrorMessage>          </properties> diff --git a/interface-definitions/protocols-babel.xml.in b/interface-definitions/protocols-babel.xml.in index b3377aac1..49fffe230 100644 --- a/interface-definitions/protocols-babel.xml.in +++ b/interface-definitions/protocols-babel.xml.in @@ -206,7 +206,7 @@                          <script>${vyos_completion_dir}/list_interfaces</script>                        </completionHelp>                        <constraint> -                        #include <include/constraint/interface-name.xml.in> +                        #include <include/constraint/interface-name.xml.i>                        </constraint>                      </properties>                      <children> @@ -234,7 +234,7 @@                          <script>${vyos_completion_dir}/list_interfaces</script>                        </completionHelp>                        <constraint> -                        #include <include/constraint/interface-name.xml.in> +                        #include <include/constraint/interface-name.xml.i>                        </constraint>                      </properties>                      <children> diff --git a/interface-definitions/protocols-bgp.xml.in b/interface-definitions/protocols-bgp.xml.in index e1a822999..78b461f9d 100644 --- a/interface-definitions/protocols-bgp.xml.in +++ b/interface-definitions/protocols-bgp.xml.in @@ -9,6 +9,20 @@          </properties>          <children>            #include <include/bgp/protocol-common-config.xml.i> +          <node name="address-family"> +            <children> +              <node name="l2vpn-evpn"> +                <children> +                  <leafNode name="advertise-all-vni"> +                    <properties> +                      <help>Advertise all local VNIs</help> +                      <valueless/> +                    </properties> +                  </leafNode> +                </children> +              </node> +            </children> +          </node>          </children>        </node>      </children> diff --git a/interface-definitions/protocols-failover.xml.in b/interface-definitions/protocols-failover.xml.in index 900c76eab..a8c5c717f 100644 --- a/interface-definitions/protocols-failover.xml.in +++ b/interface-definitions/protocols-failover.xml.in @@ -48,6 +48,7 @@                            <constraint>                              <validator name="ipv4-address"/>                            </constraint> +                          <multi/>                          </properties>                        </leafNode>                        <leafNode name="timeout"> diff --git a/interface-definitions/protocols-rip.xml.in b/interface-definitions/protocols-rip.xml.in index 68d2b64ca..0edd8f2ce 100644 --- a/interface-definitions/protocols-rip.xml.in +++ b/interface-definitions/protocols-rip.xml.in @@ -39,7 +39,7 @@                      <script>${vyos_completion_dir}/list_interfaces</script>                    </completionHelp>                    <constraint> -                    #include <include/constraint/interface-name.xml.in> +                    #include <include/constraint/interface-name.xml.i>                    </constraint>                  </properties>                  <children> diff --git a/interface-definitions/protocols-ripng.xml.in b/interface-definitions/protocols-ripng.xml.in index be643896f..9d4d87422 100644 --- a/interface-definitions/protocols-ripng.xml.in +++ b/interface-definitions/protocols-ripng.xml.in @@ -40,7 +40,7 @@                      <script>${vyos_completion_dir}/list_interfaces</script>                    </completionHelp>                    <constraint> -                    #include <include/constraint/interface-name.xml.in> +                    #include <include/constraint/interface-name.xml.i>                    </constraint>                  </properties>                  <children> diff --git a/interface-definitions/protocols-static-arp.xml.in b/interface-definitions/protocols-static-arp.xml.in index 63f450bd8..4b338df63 100644 --- a/interface-definitions/protocols-static-arp.xml.in +++ b/interface-definitions/protocols-static-arp.xml.in @@ -20,7 +20,7 @@                      <description>Interface name</description>                    </valueHelp>                    <constraint> -                    #include <include/constraint/interface-name.xml.in> +                    #include <include/constraint/interface-name.xml.i>                    </constraint>                  </properties>                  <children> diff --git a/interface-definitions/qos.xml.in b/interface-definitions/qos.xml.in index 9b1430ea0..c7bd8606a 100644 --- a/interface-definitions/qos.xml.in +++ b/interface-definitions/qos.xml.in @@ -17,7 +17,7 @@              <description>Interface name</description>            </valueHelp>            <constraint> -            #include <include/constraint/interface-name.xml.in> +            #include <include/constraint/interface-name.xml.i>            </constraint>          </properties>          <children> diff --git a/interface-definitions/service-monitoring-telegraf.xml.in b/interface-definitions/service-monitoring-telegraf.xml.in index 5ba932400..ae0bae900 100644 --- a/interface-definitions/service-monitoring-telegraf.xml.in +++ b/interface-definitions/service-monitoring-telegraf.xml.in @@ -74,7 +74,7 @@                          <properties>                            <help>Application client id</help>                            <constraint> -                            #include <include/constraint/alpha-numeric-hyphen-underscore.xml.in> +                            #include <include/constraint/alpha-numeric-hyphen-underscore.xml.i>                            </constraint>                            <constraintErrorMessage>Client-id is limited to alphanumerical characters and can contain hyphen and underscores</constraintErrorMessage>                          </properties> @@ -83,7 +83,7 @@                          <properties>                            <help>Application client secret</help>                            <constraint> -                            #include <include/constraint/alpha-numeric-hyphen-underscore.xml.in> +                            #include <include/constraint/alpha-numeric-hyphen-underscore.xml.i>                            </constraint>                            <constraintErrorMessage>Client-secret is limited to alphanumerical characters and can contain hyphen and underscores</constraintErrorMessage>                          </properties> @@ -92,7 +92,7 @@                          <properties>                            <help>Set tenant id</help>                            <constraint> -                            #include <include/constraint/alpha-numeric-hyphen-underscore.xml.in> +                            #include <include/constraint/alpha-numeric-hyphen-underscore.xml.i>                            </constraint>                            <constraintErrorMessage>Tenant-id is limited to alphanumerical characters and can contain hyphen and underscores</constraintErrorMessage>                          </properties> @@ -107,7 +107,7 @@                          <description>Remote database name</description>                        </valueHelp>                        <constraint> -                        #include <include/constraint/alpha-numeric-hyphen-underscore.xml.in> +                        #include <include/constraint/alpha-numeric-hyphen-underscore.xml.i>                        </constraint>                        <constraintErrorMessage>Database is limited to alphanumerical characters and can contain hyphen and underscores</constraintErrorMessage>                      </properties> @@ -140,7 +140,7 @@                          <description>Table name</description>                        </valueHelp>                        <constraint> -                        #include <include/constraint/alpha-numeric-hyphen-underscore.xml.in> +                        #include <include/constraint/alpha-numeric-hyphen-underscore.xml.i>                        </constraint>                        <constraintErrorMessage>Table is limited to alphanumerical characters and can contain hyphen and underscores</constraintErrorMessage>                      </properties> diff --git a/interface-definitions/service-upnp.xml.in b/interface-definitions/service-upnp.xml.in index 9e222d29a..1b2e00d91 100644 --- a/interface-definitions/service-upnp.xml.in +++ b/interface-definitions/service-upnp.xml.in @@ -24,7 +24,7 @@                  <script>${vyos_completion_dir}/list_interfaces</script>                </completionHelp>                <constraint> -                #include <include/constraint/interface-name.xml.in> +                #include <include/constraint/interface-name.xml.i>                </constraint>              </properties>            </leafNode> @@ -119,7 +119,7 @@                </valueHelp>                <multi/>                <constraint> -                #include <include/constraint/interface-name.xml.in> +                #include <include/constraint/interface-name.xml.i>                  <validator name="ipv4-address"/>                  <validator name="ipv4-prefix"/>                  <validator name="ipv6-address"/> diff --git a/interface-definitions/service-webproxy.xml.in b/interface-definitions/service-webproxy.xml.in index a315aa2ef..b24997816 100644 --- a/interface-definitions/service-webproxy.xml.in +++ b/interface-definitions/service-webproxy.xml.in @@ -538,11 +538,7 @@                            <multi/>                          </properties>                        </leafNode> -                      <leafNode name="description"> -                        <properties> -                          <help>Description for source-group</help> -                        </properties> -                      </leafNode> +                      #include <include/generic-description.xml.i>                        <leafNode name="domain">                          <properties>                            <help>Domain for source-group</help> @@ -644,11 +640,7 @@                            </leafNode>                          </children>                        </tagNode> -                      <leafNode name="description"> -                        <properties> -                          <help>Time-period description</help> -                        </properties> -                      </leafNode> +                      #include <include/generic-description.xml.i>                      </children>                    </tagNode>                  </children> diff --git a/interface-definitions/snmp.xml.in b/interface-definitions/snmp.xml.in index 592db7f4e..559e09388 100644 --- a/interface-definitions/snmp.xml.in +++ b/interface-definitions/snmp.xml.in @@ -78,15 +78,7 @@                <constraintErrorMessage>Contact information is limited to 255 characters or less</constraintErrorMessage>              </properties>            </leafNode> -          <leafNode name="description"> -            <properties> -              <help>Description information</help> -              <constraint> -                <regex>.{1,255}</regex> -              </constraint> -              <constraintErrorMessage>Description is limited to 255 characters or less</constraintErrorMessage> -            </properties> -          </leafNode> +          #include <include/generic-description.xml.i>            <tagNode name="listen-address">              <properties>                <help>IP address to listen for incoming SNMP requests</help> diff --git a/interface-definitions/system-config-mgmt.xml.in b/interface-definitions/system-config-mgmt.xml.in index 1f852d284..716332d2a 100644 --- a/interface-definitions/system-config-mgmt.xml.in +++ b/interface-definitions/system-config-mgmt.xml.in @@ -32,7 +32,7 @@                    <constraint>                      <validator name="ipv4-address"/>                      <validator name="ipv6-address"/> -                    #include <include/constraint/interface-name.xml.in> +                    #include <include/constraint/interface-name.xml.i>                    </constraint>                  </properties>                </leafNode> diff --git a/interface-definitions/system-ip.xml.in b/interface-definitions/system-ip.xml.in index e00dbf252..abdede979 100644 --- a/interface-definitions/system-ip.xml.in +++ b/interface-definitions/system-ip.xml.in @@ -48,6 +48,7 @@                </leafNode>              </children>            </node> +          #include <include/system-ip-protocol.xml.i>          </children>        </node>      </children> diff --git a/interface-definitions/system-ipv6.xml.in b/interface-definitions/system-ipv6.xml.in index 63260d00c..e17e1c01c 100644 --- a/interface-definitions/system-ipv6.xml.in +++ b/interface-definitions/system-ipv6.xml.in @@ -36,6 +36,7 @@                #include <include/arp-ndp-table-size.xml.i>              </children>            </node> +          #include <include/system-ipv6-protocol.xml.i>            <leafNode name="strict-dad">              <properties>                <help>Disable IPv6 operation on interface when DAD fails on LL addr</help> diff --git a/interface-definitions/system-login.xml.in b/interface-definitions/system-login.xml.in index b00741ffe..258913929 100644 --- a/interface-definitions/system-login.xml.in +++ b/interface-definitions/system-login.xml.in @@ -225,6 +225,19 @@                #include <include/interface/vrf.xml.i>              </children>            </node> +          <leafNode name="max-login-session"> +            <properties> +              <help>Maximum number of all login sessions</help> +              <valueHelp> +                <format>u32:1-65536</format> +                <description>Maximum number of all login sessions</description> +              </valueHelp> +              <constraint> +                <validator name="numeric" argument="--range 1-65536"/> +              </constraint> +              <constraintErrorMessage>Maximum logins must be between 1 and 65536</constraintErrorMessage> +            </properties> +          </leafNode>            <leafNode name="timeout">              <properties>                <help>Session timeout</help> diff --git a/interface-definitions/system-sflow.xml.in b/interface-definitions/system-sflow.xml.in index 335181fe1..9c748c24a 100644 --- a/interface-definitions/system-sflow.xml.in +++ b/interface-definitions/system-sflow.xml.in @@ -42,7 +42,7 @@                  <description>Interface name</description>                </valueHelp>                <constraint> -                #include <include/constraint/interface-name.xml.in> +                #include <include/constraint/interface-name.xml.i>                </constraint>              </properties>            </leafNode> diff --git a/interface-definitions/vpn-ipsec.xml.in b/interface-definitions/vpn-ipsec.xml.in index 1b3a5532e..64cfbda08 100644 --- a/interface-definitions/vpn-ipsec.xml.in +++ b/interface-definitions/vpn-ipsec.xml.in @@ -357,11 +357,11 @@                  <properties>                    <help>IKE lifetime</help>                    <valueHelp> -                    <format>u32:30-86400</format> +                    <format>u32:0-86400</format>                      <description>IKE lifetime in seconds</description>                    </valueHelp>                    <constraint> -                    <validator name="numeric" argument="--range 30-86400"/> +                    <validator name="numeric" argument="--range 0-86400"/>                    </constraint>                  </properties>                  <defaultValue>28800</defaultValue> diff --git a/interface-definitions/vpn-l2tp.xml.in b/interface-definitions/vpn-l2tp.xml.in index 0a92017bd..6b64c5f5d 100644 --- a/interface-definitions/vpn-l2tp.xml.in +++ b/interface-definitions/vpn-l2tp.xml.in @@ -124,11 +124,7 @@                  </children>                </node>                #include <include/accel-ppp/client-ipv6-pool.xml.i> -              <leafNode name="description"> -                <properties> -                  <help>Description for L2TP remote-access settings</help> -                </properties> -              </leafNode> +              #include <include/generic-description.xml.i>                #include <include/dhcp-interface.xml.i>                <leafNode name="idle">                  <properties> diff --git a/interface-definitions/vpn-pptp.xml.in b/interface-definitions/vpn-pptp.xml.in index 00ffd26f9..5a8b4a78a 100644 --- a/interface-definitions/vpn-pptp.xml.in +++ b/interface-definitions/vpn-pptp.xml.in @@ -108,9 +108,13 @@                        </tagNode>                      </children>                    </node> +                  <node name="radius"> +                    <children> +                      #include <include/accel-ppp/radius-additions-rate-limit.xml.i> +                    </children> +                  </node>                    #include <include/radius-auth-server-ipv4.xml.i>                    #include <include/accel-ppp/radius-additions.xml.i> -                  #include <include/accel-ppp/radius-additions-rate-limit.xml.i>                  </children>                </node>              </children> diff --git a/interface-definitions/vrf.xml.in b/interface-definitions/vrf.xml.in index 96c6d8be2..a7efe146a 100644 --- a/interface-definitions/vrf.xml.in +++ b/interface-definitions/vrf.xml.in @@ -34,6 +34,7 @@              </properties>              <children>                #include <include/interface/disable-forwarding.xml.i> +              #include <include/system-ip-protocol.xml.i>              </children>            </node>            <node name="ipv6"> @@ -42,6 +43,7 @@              </properties>              <children>                #include <include/interface/disable-forwarding.xml.i> +              #include <include/system-ipv6-protocol.xml.i>              </children>            </node>            <node name="protocols"> @@ -119,20 +121,7 @@                <constraintErrorMessage>VRF routing table must be in range from 100 to 65535</constraintErrorMessage>              </properties>            </leafNode> -          <leafNode name="vni" owner="${vyos_conf_scripts_dir}/vrf_vni.py"> -            <properties> -              <help>Virtual Network Identifier</help> -              <!-- priority must be after BGP --> -              <priority>822</priority> -              <valueHelp> -                <format>u32:0-16777214</format> -                <description>VXLAN virtual network identifier</description> -              </valueHelp> -              <constraint> -                <validator name="numeric" argument="--range 0-16777214"/> -              </constraint> -            </properties> -          </leafNode> +          #include <include/vni.xml.i>          </children>        </tagNode>      </children> diff --git a/interface-definitions/xml-component-version.xml.in b/interface-definitions/xml-component-version.xml.in index 2e6506efc..e05f64643 100644 --- a/interface-definitions/xml-component-version.xml.in +++ b/interface-definitions/xml-component-version.xml.in @@ -33,6 +33,7 @@    #include <include/version/pptp-version.xml.i>    #include <include/version/qos-version.xml.i>    #include <include/version/quagga-version.xml.i> +  #include <include/version/rip-version.xml.i>    #include <include/version/rpki-version.xml.i>    #include <include/version/salt-version.xml.i>    #include <include/version/snmp-version.xml.i> diff --git a/op-mode-definitions/include/bgp/afi-ipv4-ipv6-common.xml.i b/op-mode-definitions/include/bgp/afi-ipv4-ipv6-common.xml.i index 7dbc4fde5..820d507fd 100644 --- a/op-mode-definitions/include/bgp/afi-ipv4-ipv6-common.xml.i +++ b/op-mode-definitions/include/bgp/afi-ipv4-ipv6-common.xml.i @@ -195,6 +195,12 @@          </leafNode>        </children>      </node> +    <leafNode name="filtered-routes"> +      <properties> +        <help>Show filtered routes from BGP neighbor</help> +      </properties> +      <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> +    </leafNode>      <leafNode name="received-routes">        <properties>          <help>Show received routes from BGP neighbor</help> diff --git a/op-mode-definitions/include/bgp/evpn-type-1.xml.i b/op-mode-definitions/include/bgp/evpn-type-1.xml.i new file mode 100644 index 000000000..b5097c8b1 --- /dev/null +++ b/op-mode-definitions/include/bgp/evpn-type-1.xml.i @@ -0,0 +1,8 @@ +<!-- included start from bgp/evpn-type-1.xml.i --> +<leafNode name="1"> +  <properties> +    <help>EAD (Type-1) route</help> +  </properties> +  <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> +</leafNode> +<!-- included end --> diff --git a/op-mode-definitions/include/bgp/evpn-type-2.xml.i b/op-mode-definitions/include/bgp/evpn-type-2.xml.i new file mode 100644 index 000000000..827298d62 --- /dev/null +++ b/op-mode-definitions/include/bgp/evpn-type-2.xml.i @@ -0,0 +1,8 @@ +<!-- included start from bgp/evpn-type-2.xml.i --> +<leafNode name="2"> +  <properties> +    <help>MAC-IP (Type-2) route</help> +  </properties> +  <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> +</leafNode> +<!-- included end --> diff --git a/op-mode-definitions/include/bgp/evpn-type-3.xml.i b/op-mode-definitions/include/bgp/evpn-type-3.xml.i new file mode 100644 index 000000000..ae90b2e5c --- /dev/null +++ b/op-mode-definitions/include/bgp/evpn-type-3.xml.i @@ -0,0 +1,8 @@ +<!-- included start from bgp/evpn-type-3.xml.i --> +<leafNode name="3"> +  <properties> +    <help>Multicast (Type-3) route</help> +  </properties> +  <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> +</leafNode> +<!-- included end --> diff --git a/op-mode-definitions/include/bgp/evpn-type-4.xml.i b/op-mode-definitions/include/bgp/evpn-type-4.xml.i new file mode 100644 index 000000000..7248b4753 --- /dev/null +++ b/op-mode-definitions/include/bgp/evpn-type-4.xml.i @@ -0,0 +1,8 @@ +<!-- included start from bgp/evpn-type-4.xml.i --> +<leafNode name="4"> +  <properties> +    <help>Ethernet Segment (Type-4) route</help> +  </properties> +  <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> +</leafNode> +<!-- included end --> diff --git a/op-mode-definitions/include/bgp/evpn-type-5.xml.i b/op-mode-definitions/include/bgp/evpn-type-5.xml.i new file mode 100644 index 000000000..e3a72168a --- /dev/null +++ b/op-mode-definitions/include/bgp/evpn-type-5.xml.i @@ -0,0 +1,8 @@ +<!-- included start from bgp/evpn-type-5.xml.i --> +<leafNode name="5"> +  <properties> +    <help>Prefix (Type-5) route</help> +  </properties> +  <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> +</leafNode> +<!-- included end --> diff --git a/op-mode-definitions/include/bgp/evpn-type-ead.xml.i b/op-mode-definitions/include/bgp/evpn-type-ead.xml.i new file mode 100644 index 000000000..452de2f9a --- /dev/null +++ b/op-mode-definitions/include/bgp/evpn-type-ead.xml.i @@ -0,0 +1,8 @@ +<!-- included start from bgp/evpn-type-ead.xml.i --> +<leafNode name="ead"> +  <properties> +    <help>EAD (Type-1) route</help> +  </properties> +  <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> +</leafNode> +<!-- included end --> diff --git a/op-mode-definitions/include/bgp/evpn-type-es.xml.i b/op-mode-definitions/include/bgp/evpn-type-es.xml.i new file mode 100644 index 000000000..50c40151a --- /dev/null +++ b/op-mode-definitions/include/bgp/evpn-type-es.xml.i @@ -0,0 +1,8 @@ +<!-- included start from bgp/evpn-type-es.xml.i --> +<leafNode name="es"> +  <properties> +    <help>Ethernet Segment (Type-4) route</help> +  </properties> +  <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> +</leafNode> +<!-- included end --> diff --git a/op-mode-definitions/include/bgp/evpn-type-macip.xml.i b/op-mode-definitions/include/bgp/evpn-type-macip.xml.i new file mode 100644 index 000000000..6f601eb3f --- /dev/null +++ b/op-mode-definitions/include/bgp/evpn-type-macip.xml.i @@ -0,0 +1,8 @@ +<!-- included start from bgp/evpn-type-macip.xml.i --> +<leafNode name="macip"> +  <properties> +    <help>MAC-IP (Type-2) route</help> +  </properties> +  <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> +</leafNode> +<!-- included end --> diff --git a/op-mode-definitions/include/bgp/evpn-type-multicast.xml.i b/op-mode-definitions/include/bgp/evpn-type-multicast.xml.i new file mode 100644 index 000000000..5194dbb56 --- /dev/null +++ b/op-mode-definitions/include/bgp/evpn-type-multicast.xml.i @@ -0,0 +1,8 @@ +<!-- included start from bgp/evpn-type-multicast.xml.i --> +<leafNode name="multicast"> +  <properties> +    <help>Multicast (Type-3) route</help> +  </properties> +  <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> +</leafNode> +<!-- included end --> diff --git a/op-mode-definitions/include/bgp/evpn-type-prefix.xml.i b/op-mode-definitions/include/bgp/evpn-type-prefix.xml.i new file mode 100644 index 000000000..d5054d86b --- /dev/null +++ b/op-mode-definitions/include/bgp/evpn-type-prefix.xml.i @@ -0,0 +1,8 @@ +<!-- included start from bgp/evpn-type-prefix.xml.i --> +<leafNode name="prefix"> +  <properties> +    <help>Prefix (Type-5) route</help> +  </properties> +  <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> +</leafNode> +<!-- included end --> diff --git a/op-mode-definitions/include/bgp/show-bgp-common.xml.i b/op-mode-definitions/include/bgp/show-bgp-common.xml.i index c9a112fca..de794a879 100644 --- a/op-mode-definitions/include/bgp/show-bgp-common.xml.i +++ b/op-mode-definitions/include/bgp/show-bgp-common.xml.i @@ -171,66 +171,16 @@                  <help>Specify Route type</help>                </properties>                <children> -                <leafNode name="1"> -                  <properties> -                    <help>EAD (Type-1) route</help> -                  </properties> -                  <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> -                </leafNode> -                <leafNode name="2"> -                  <properties> -                    <help>MAC-IP (Type-2) route</help> -                  </properties> -                  <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> -                </leafNode> -                <leafNode name="3"> -                  <properties> -                    <help>Multicast (Type-3) route</help> -                  </properties> -                  <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> -                </leafNode> -                <leafNode name="4"> -                  <properties> -                    <help>Ethernet Segment (Type-4) route</help> -                  </properties> -                  <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> -                </leafNode> -                <leafNode name="5"> -                  <properties> -                    <help>Prefix (Type-5) route</help> -                  </properties> -                  <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> -                </leafNode> -                <leafNode name="ead"> -                  <properties> -                    <help>EAD (Type-1) route</help> -                  </properties> -                  <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> -                </leafNode> -                <leafNode name="es"> -                  <properties> -                    <help>Ethernet Segment (Type-4) route</help> -                  </properties> -                  <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> -                </leafNode> -                <leafNode name="macip"> -                  <properties> -                    <help>MAC-IP (Type-2) route</help> -                  </properties> -                  <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> -                </leafNode> -                <leafNode name="multicast"> -                  <properties> -                    <help>Multicast (Type-3) route</help> -                  </properties> -                  <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> -                </leafNode> -                <leafNode name="prefix"> -                  <properties> -                    <help>Prefix (Type-5) route</help> -                  </properties> -                  <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> -                </leafNode> +                #include <include/bgp/evpn-type-1.xml.i> +                #include <include/bgp/evpn-type-2.xml.i> +                #include <include/bgp/evpn-type-3.xml.i> +                #include <include/bgp/evpn-type-4.xml.i> +                #include <include/bgp/evpn-type-5.xml.i> +                #include <include/bgp/evpn-type-ead.xml.i> +                #include <include/bgp/evpn-type-es.xml.i> +                #include <include/bgp/evpn-type-macip.xml.i> +                #include <include/bgp/evpn-type-multicast.xml.i> +                #include <include/bgp/evpn-type-prefix.xml.i>                </children>              </node>              #include <include/vni-tagnode-all.xml.i> diff --git a/op-mode-definitions/include/bgp/show-ip-bgp-common.xml.i b/op-mode-definitions/include/bgp/show-ip-bgp-common.xml.i index 36cc9a3fa..db9021f3e 100644 --- a/op-mode-definitions/include/bgp/show-ip-bgp-common.xml.i +++ b/op-mode-definitions/include/bgp/show-ip-bgp-common.xml.i @@ -93,6 +93,12 @@                </properties>                <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>              </leafNode> +            <leafNode name="filtered-routes"> +              <properties> +                <help>Show the filtered routes from neighbor</help> +              </properties> +              <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> +            </leafNode>              <leafNode name="received-routes">                <properties>                  <help>Show the received routes from neighbor</help> diff --git a/op-mode-definitions/include/isis-common.xml.i b/op-mode-definitions/include/isis-common.xml.i index 95a171515..e94d868e8 100644 --- a/op-mode-definitions/include/isis-common.xml.i +++ b/op-mode-definitions/include/isis-common.xml.i @@ -4,12 +4,7 @@      <help>Show IS-IS link state database</help>    </properties>    <children> -    <leafNode name="detail"> -      <properties> -        <help>Show detailed information</help> -      </properties> -      <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> -    </leafNode> +    #include <include/vtysh-generic-detail.xml.i>    </children>    <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>  </node> @@ -36,27 +31,22 @@      </completionHelp>    </properties>    <children> -    <leafNode name="detail"> -      <properties> -        <help>Show detailed information</help> -      </properties> -      <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> -    </leafNode> +    #include <include/vtysh-generic-detail.xml.i>    </children>    <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>  </node> -<tagNode name="interface"> +#include <include/vtysh-generic-interface-tagNode.xml.i> +<node name="mpls">    <properties> -    <help>Show specific IS-IS interface</help> -    <completionHelp> -      <script>${vyos_completion_dir}/list_interfaces</script> -    </completionHelp> +    <help>Show MPLS information</help>    </properties> -  <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> -</tagNode> +  <children> +  #include <include/ldp-sync.xml.i> +  </children> +</node>  <node name="mpls-te">    <properties> -    <help>Show IS-IS MPLS traffic engineering information</help> +    <help>Show MPLS traffic engineering information</help>    </properties>    <children>      <leafNode name="router"> @@ -71,15 +61,7 @@        </properties>        <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>      </leafNode> -    <tagNode name="interface"> -      <properties> -        <help>Show specific IS-IS interface</help> -        <completionHelp> -          <script>${vyos_completion_dir}/list_interfaces</script> -        </completionHelp> -      </properties> -      <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> -    </tagNode> +    #include <include/vtysh-generic-interface-tagNode.xml.i>    </children>  </node>  <node name="neighbor"> @@ -87,14 +69,9 @@      <help>Show IS-IS neighbor adjacencies</help>    </properties>    <children> -    <leafNode name="detail"> -      <properties> -        <help>Show detailed information</help> -      </properties> -      <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> -    </leafNode> +    #include <include/vtysh-generic-detail.xml.i>    </children> -  <command>vtysh -c "show isis neighbor"</command> +  <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>  </node>  <tagNode name="neighbor">    <properties> @@ -122,8 +99,14 @@        </properties>        <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>      </leafNode> +    <leafNode name="prefix-sid"> +     <properties> +       <help>Show Prefix-SID information</help> +     </properties> +     <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> +   </leafNode>    </children> -  <command>vtysh -c "show isis route"</command> +  <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>  </node>  <node name="segment-routing">    <properties> @@ -136,12 +119,6 @@        </properties>        <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>      </leafNode> -    <leafNode name="prefix-sids"> -      <properties> -        <help>Show prefix segment IDs</help> -      </properties> -      <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> -    </leafNode>    </children>  </node>  <leafNode name="spf-delay-ietf"> @@ -176,4 +153,4 @@    </children>    <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>  </node> -<!-- included end --> +<!-- included end -->
\ No newline at end of file diff --git a/op-mode-definitions/include/ldp-sync.xml.i b/op-mode-definitions/include/ldp-sync.xml.i new file mode 100644 index 000000000..b7b04e7e5 --- /dev/null +++ b/op-mode-definitions/include/ldp-sync.xml.i @@ -0,0 +1,11 @@ +<!-- included start from ldp-sync.xml.i --> +<node name="ldp-sync"> +  <properties> +    <help>Show LDP-IGP synchronization information</help> +  </properties> +  <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> +  <children> +    #include <include/vtysh-generic-interface-tagNode.xml.i> +  </children> +</node> +<!-- included end -->
\ No newline at end of file diff --git a/op-mode-definitions/include/ospf-common.xml.i b/op-mode-definitions/include/ospf-common.xml.i index 14b7839ec..979ffb07e 100644 --- a/op-mode-definitions/include/ospf-common.xml.i +++ b/op-mode-definitions/include/ospf-common.xml.i @@ -508,15 +508,15 @@    </properties>    <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>  </node> -<tagNode name="interface"> +#include <include/vtysh-generic-interface-tagNode.xml.i> +<node name="mpls">    <properties> -    <help>Show IPv4 OSPF information for specified interface</help> -    <completionHelp> -      <script>${vyos_completion_dir}/list_interfaces</script> -    </completionHelp> +    <help>Show MPLS information</help>    </properties> -  <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> -</tagNode> +  <children> +  #include <include/ldp-sync.xml.i> +  </children> +</node>  <node name="neighbor">    <properties>      <help>Show IPv4 OSPF neighbor information</help> @@ -556,3 +556,4 @@    </children>  </node>  <!-- included end --> + diff --git a/op-mode-definitions/include/vtysh-generic-interface-tagNode.xml.i b/op-mode-definitions/include/vtysh-generic-interface-tagNode.xml.i new file mode 100644 index 000000000..e95961177 --- /dev/null +++ b/op-mode-definitions/include/vtysh-generic-interface-tagNode.xml.i @@ -0,0 +1,11 @@ +<!-- included start from vtysh-generic-interface.xml.i --> +<tagNode name="interface"> +  <properties> +    <help>Show information about specific interface</help> +    <completionHelp> +      <script>${vyos_completion_dir}/list_interfaces</script> +    </completionHelp> +  </properties> +  <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> +</tagNode> +<!-- included end --> diff --git a/op-mode-definitions/sflow.xml.in b/op-mode-definitions/sflow.xml.in new file mode 100644 index 000000000..9f02dacda --- /dev/null +++ b/op-mode-definitions/sflow.xml.in @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- sflow op mode commands --> +<interfaceDefinition> +  <node name="show"> +    <children> +      <node name="sflow"> +        <properties> +          <help>Show sFlow statistics</help> +        </properties> +        <!-- requires sudo, do not remove it --> +        <command>sudo ${vyos_op_scripts_dir}/sflow.py show</command> +      </node> +    </children> +  </node> +</interfaceDefinition> diff --git a/op-mode-definitions/show-bgp.xml.in b/op-mode-definitions/show-bgp.xml.in index 974147621..3c212614c 100644 --- a/op-mode-definitions/show-bgp.xml.in +++ b/op-mode-definitions/show-bgp.xml.in @@ -51,6 +51,33 @@              </properties>              <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>            </leafNode> +          #include <include/vni-tagnode-all.xml.i> +          <tagNode name="vni"> +            <children> +              <tagNode name="vtep"> +                <properties> +                  <help>Remote VTEP IP address</help> +                  <completionHelp> +                    <list><x.x.x.x></list> +                  </completionHelp> +                </properties> +                <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> +              </tagNode> +              <node name="type"> +                <properties> +                  <help>Display number of prefixes for all afi/safi</help> +                </properties> +                <children> +                  #include <include/bgp/evpn-type-1.xml.i> +                  #include <include/bgp/evpn-type-2.xml.i> +                  #include <include/bgp/evpn-type-3.xml.i> +                  #include <include/bgp/evpn-type-ead.xml.i> +                  #include <include/bgp/evpn-type-macip.xml.i> +                  #include <include/bgp/evpn-type-multicast.xml.i> +                </children> +              </node> +            </children> +          </tagNode>            <leafNode name="vrf">              <properties>                <help>Show BGP VRF information</help> diff --git a/op-mode-definitions/show-log.xml.in b/op-mode-definitions/show-log.xml.in index 7f6469ca9..7663e4c00 100644 --- a/op-mode-definitions/show-log.xml.in +++ b/op-mode-definitions/show-log.xml.in @@ -8,6 +8,12 @@          </properties>          <command>journalctl --no-hostname --boot</command>          <children> +          <leafNode name="audit"> +            <properties> +              <help>Show audit logs</help> +            </properties> +            <command>cat /var/log/audit/audit.log</command> +          </leafNode>            <leafNode name="all">              <properties>                <help>Show contents of all master log files</help> diff --git a/op-mode-definitions/show-techsupport_report.xml.in b/op-mode-definitions/show-techsupport_report.xml.in new file mode 100644 index 000000000..aa51eacd9 --- /dev/null +++ b/op-mode-definitions/show-techsupport_report.xml.in @@ -0,0 +1,17 @@ +<?xml version="1.0"?> +<interfaceDefinition> +  <node name="show"> +    <children> +      <node name="tech-support"> +        <children> +          <node name="report"> +            <properties> +              <help>Show consolidated tech-support report (contains private information)</help> +            </properties> +            <command>${vyos_op_scripts_dir}/show_techsupport_report.py</command> +          </node> +        </children> +      </node> +    </children> +  </node> +</interfaceDefinition> diff --git a/op-mode-definitions/vpn-ipsec.xml.in b/op-mode-definitions/vpn-ipsec.xml.in index 5baaec7ce..5a7e6dd63 100644 --- a/op-mode-definitions/vpn-ipsec.xml.in +++ b/op-mode-definitions/vpn-ipsec.xml.in @@ -14,7 +14,7 @@              <children>                <tagNode name="profile">                  <properties> -                  <help>Reset all tunnels for given DMVPN profile</help> +                  <help>Reset a specific tunnel for given DMVPN profile</help>                    <completionHelp>                      <path>vpn ipsec profile</path>                    </completionHelp> @@ -23,11 +23,24 @@                    <tagNode name="tunnel">                      <properties>                        <help>Reset a specific tunnel for given DMVPN profile</help> +                      <completionHelp> +                        <script>sudo ${vyos_completion_dir}/list_ipsec_profile_tunnels.py --profile ${COMP_WORDS[4]}</script> +                      </completionHelp>                      </properties> -                    <command>sudo ${vyos_op_scripts_dir}/vpn_ipsec.py --action="reset-profile" --name="$6" --tunnel="$8"</command> +                    <children> +                      <tagNode name="remote-host"> +                        <properties> +                          <help>Reset a specific tunnel for given DMVPN NBMA</help> +                          <completionHelp> +                            <list><x.x.x.x> <h:h:h:h:h:h:h:h></list> +                          </completionHelp> +                        </properties> +                        <command>sudo ${vyos_op_scripts_dir}/ipsec.py reset_profile_dst --profile="$5" --tunnel="$7" --nbma_dst="$9"</command> +                      </tagNode> +                    </children> +                    <command>sudo ${vyos_op_scripts_dir}/ipsec.py reset_profile_all --profile="$5" --tunnel="$7"</command>                    </tagNode>                  </children> -                <command>sudo ${vyos_op_scripts_dir}/vpn_ipsec.py --action="reset-profile" --name="$6" --tunnel="all"</command>                </tagNode>                <node name="remote-access">                  <properties> diff --git a/python/vyos/ifconfig/interface.py b/python/vyos/ifconfig/interface.py index fc33430eb..f62b9f7d2 100644 --- a/python/vyos/ifconfig/interface.py +++ b/python/vyos/ifconfig/interface.py @@ -1709,6 +1709,14 @@ class VLANIf(Interface):          if self.exists(f'{self.ifname}'):              return +        # If source_interface or vlan_id was not explicitly defined (e.g. when +        # calling  VLANIf('eth0.1').remove() we can define source_interface and +        # vlan_id here, as it's quiet obvious that it would be eth0 in that case. +        if 'source_interface' not in self.config: +            self.config['source_interface'] = '.'.join(self.ifname.split('.')[:-1]) +        if 'vlan_id' not in self.config: +            self.config['vlan_id'] = self.ifname.split('.')[-1] +          cmd = 'ip link add link {source_interface} name {ifname} type vlan id {vlan_id}'          if 'protocol' in self.config:              cmd += ' protocol {protocol}' diff --git a/python/vyos/ipsec.py b/python/vyos/ipsec.py index cb7c39ff6..bb5611025 100644 --- a/python/vyos/ipsec.py +++ b/python/vyos/ipsec.py @@ -139,3 +139,41 @@ def terminate_vici_by_name(ike_name: str, child_name: str) -> None:          else:              raise ViciCommandError(                  f'Failed to terminate SA for IKE {ike_name}') + + +def vici_initiate(ike_sa_name: str, child_sa_name: str, src_addr: str, +                  dst_addr: str) -> bool: +    """Initiate IKE SA connection with specific peer + +    Args: +        ike_sa_name (str): an IKE SA connection name +        child_sa_name (str): a child SA profile name +        src_addr (str): source address +        dst_addr (str): remote address + +    Returns: +        bool: a result of initiation command +    """ +    from vici import Session as vici_session + +    try: +        session = vici_session() +    except Exception: +        raise ViciInitiateError("IPsec not initialized") + +    try: +        session_generator = session.initiate({ +            'ike': ike_sa_name, +            'child': child_sa_name, +            'timeout': '-1', +            'my-host': src_addr, +            'other-host': dst_addr +        }) +        # a dummy `for` loop is required because of requirements +        # from vici. Without a full iteration on the output, the +        # command to vici may not be executed completely +        for _ in session_generator: +            pass +        return True +    except Exception: +        raise ViciCommandError(f'Failed to initiate SA for IKE {ike_sa_name}')
\ No newline at end of file diff --git a/smoketest/configs/egb-igp-route-maps b/smoketest/configs/egb-igp-route-maps new file mode 100644 index 000000000..ca36691d4 --- /dev/null +++ b/smoketest/configs/egb-igp-route-maps @@ -0,0 +1,127 @@ +interfaces { +    ethernet eth0 { +        address 192.0.2.1/25 +        duplex auto +        smp-affinity auto +        speed auto +    } +    ethernet eth1 { +        address 192.0.2.129/25 +        address 2001:db8::1234/64 +        duplex auto +        smp-affinity auto +        speed auto +    } +    loopback lo { +    } +} +policy { +    route-map zebra-bgp { +        rule 10 { +            action permit +        } +    } +    route-map zebra-isis { +        rule 10 { +            action permit +        } +    } +    route-map zebra-ospf { +        rule 10 { +            action permit +        } +    } +    route-map zebra-ospfv3 { +        rule 10 { +            action permit +        } +    } +    route-map zebra-ripng { +        rule 10 { +            action permit +        } +    } +    route-map zebra-static { +        rule 10 { +            action permit +        } +    } +} +protocols { +    bgp 100 { +        route-map zebra-bgp +    } +    isis { +        interface eth0 { +        } +        net 49.0001.1921.6800.1002.00 +        route-map zebra-isis +    } +    ospf { +        area 0 { +            network 192.0.2.0/25 +            network 192.0.2.128/25 +        } +        log-adjacency-changes { +        } +        parameters { +            abr-type cisco +            router-id 1.1.1.1 +        } +        passive-interface default +        passive-interface-exclude eth0 +        passive-interface-exclude eth1 +        route-map zebra-ospf +    } +    ospfv3 { +        area 0 { +            interface eth1 +        } +        parameters { +            router-id 1.1.1.1 +        } +        route-map zebra-ospfv3 +    } +    ripng { +        interface eth1 +        route-map zebra-ripng +    } +    static { +        route-map zebra-static +    } +} +system { +    config-management { +        commit-revisions 100 +    } +    console { +        device ttyS0 { +            speed 115200 +        } +    } +    host-name vyos +    login { +        user vyos { +            authentication { +                encrypted-password $6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0 +                plaintext-password "" +            } +        } +    } +    name-server 192.168.0.1 +    syslog { +        global { +            archive { +                file 5 +                size 512 +            } +            facility all { +                level info +            } +        } +    } +    time-zone Europe/Berlin +} +// Warning: Do not remove the following line. +// vyos-config-version: "broadcast-relay@1:cluster@1:config-management@1:conntrack@3:conntrack-sync@2:dhcp-relay@2:dhcp-server@6:dhcpv6-server@1:dns-forwarding@3:firewall@5:https@2:interfaces@22:ipoe-server@1:ipsec@5:isis@1:l2tp@3:lldp@1:mdns@1:nat@5:ntp@1:pppoe-server@5:pptp@2:qos@1:quagga@8:rpki@1:salt@1:snmp@2:ssh@2:sstp@3:system@21:vrrp@2:vyos-accel-ppp@2:wanloadbalance@3:webproxy@2:zone-policy@1" +// Release version: 1.3.2 diff --git a/smoketest/scripts/cli/test_firewall.py b/smoketest/scripts/cli/test_firewall.py index e071b7df9..99d3b3ca1 100755 --- a/smoketest/scripts/cli/test_firewall.py +++ b/smoketest/scripts/cli/test_firewall.py @@ -198,6 +198,7 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase):      def test_ipv4_basic_rules(self):          name = 'smoketest'          interface = 'eth0' +        interface_wc = 'l2tp*'          mss_range = '501-1460'          conn_mark = '555' @@ -240,6 +241,7 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase):          self.cli_set(['firewall', 'name', name, 'rule', '6', 'connection-mark', conn_mark])          self.cli_set(['firewall', 'interface', interface, 'in', 'name', name]) +        self.cli_set(['firewall', 'interface', interface_wc, 'in', 'name', name])          self.cli_commit() @@ -247,6 +249,7 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase):          nftables_search = [              [f'iifname "{interface}"', f'jump NAME_{name}'], +            [f'iifname "{interface_wc}"', f'jump NAME_{name}'],              ['saddr 172.16.20.10', 'daddr 172.16.10.10', 'log prefix "[smoketest-1-A]" log level debug', 'ip ttl 15', 'return'],              ['tcp flags syn / syn,ack', 'tcp dport 8888', 'log prefix "[smoketest-2-R]" log level err', 'ip ttl > 102', 'reject'],              ['tcp dport 22', 'limit rate 5/minute', 'return'], diff --git a/smoketest/scripts/cli/test_interfaces_openvpn.py b/smoketest/scripts/cli/test_interfaces_openvpn.py index b2143d16e..c80c7cf80 100755 --- a/smoketest/scripts/cli/test_interfaces_openvpn.py +++ b/smoketest/scripts/cli/test_interfaces_openvpn.py @@ -1,6 +1,6 @@  #!/usr/bin/env python3  # -# Copyright (C) 2020-2022 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 @@ -368,6 +368,7 @@ class TestInterfacesOpenVPN(VyOSUnitTestSHIM.TestCase):              self.cli_set(path + ['hash', auth_hash])              self.cli_set(path + ['mode', 'server'])              self.cli_set(path + ['local-port', port]) +            self.cli_set(path + ['server', 'mfa', 'totp'])              self.cli_set(path + ['server', 'subnet', subnet])              self.cli_set(path + ['server', 'topology', 'subnet'])              self.cli_set(path + ['keep-alive', 'failure-count', '5']) @@ -388,6 +389,7 @@ class TestInterfacesOpenVPN(VyOSUnitTestSHIM.TestCase):          for ii in num_range:              interface = f'vtun{ii}' +            plugin = f'plugin "/usr/lib/openvpn/openvpn-otp.so" "otp_secrets=/config/auth/openvpn/{interface}-otp-secrets otp_slop=180 totp_t0=0 totp_step=30 totp_digits=6 password_is_cr=1"'              subnet = f'192.0.{ii}.0/24'              start_addr = inc_ip(subnet, '2') @@ -411,6 +413,7 @@ class TestInterfacesOpenVPN(VyOSUnitTestSHIM.TestCase):              self.assertIn(f'topology subnet', config)              self.assertIn(f'lport {port}', config)              self.assertIn(f'push "redirect-gateway def1"', config) +            self.assertIn(f'{plugin}', config)              self.assertIn(f'keepalive 5 25', config)              # TLS options diff --git a/smoketest/scripts/cli/test_load_balancing_wan.py b/smoketest/scripts/cli/test_load_balancing_wan.py index 0e1806f66..8df3471f7 100755 --- a/smoketest/scripts/cli/test_load_balancing_wan.py +++ b/smoketest/scripts/cli/test_load_balancing_wan.py @@ -1,6 +1,6 @@  #!/usr/bin/env python3  # -# Copyright (C) 2022 VyOS maintainers and contributors +# Copyright (C) 2022-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 @@ -177,7 +177,7 @@ class TestLoadBalancingWan(VyOSUnitTestSHIM.TestCase):          nat_vyos_pre_snat_hook = """table ip nat {  	chain VYOS_PRE_SNAT_HOOK {  		type nat hook postrouting priority srcnat - 1; policy accept; -		return +		counter jump WANLOADBALANCE  	}  }""" diff --git a/smoketest/scripts/cli/test_policy_route.py b/smoketest/scripts/cli/test_policy_route.py index 4be36b134..a3df6bf4d 100755 --- a/smoketest/scripts/cli/test_policy_route.py +++ b/smoketest/scripts/cli/test_policy_route.py @@ -26,6 +26,7 @@ conn_mark_set = '111'  table_mark_offset = 0x7fffffff  table_id = '101'  interface = 'eth0' +interface_wc = 'ppp*'  interface_ip = '172.16.10.1/24'  class TestPolicyRoute(VyOSUnitTestSHIM.TestCase): @@ -236,7 +237,8 @@ class TestPolicyRoute(VyOSUnitTestSHIM.TestCase):          self.cli_set(['policy', 'route6', 'smoketest6', 'rule', '5', 'set', 'table', table_id])          self.cli_set(['policy', 'route', 'smoketest', 'interface', interface]) -        self.cli_set(['policy', 'route6', 'smoketest6', 'interface', interface]) +        self.cli_set(['policy', 'route', 'smoketest', 'interface', interface_wc]) +        self.cli_set(['policy', 'route6', 'smoketest6', 'interface', interface_wc])          self.cli_commit() @@ -244,7 +246,7 @@ class TestPolicyRoute(VyOSUnitTestSHIM.TestCase):          # IPv4          nftables_search = [ -            [f'iifname "{interface}"', 'jump VYOS_PBR_smoketest'], +            ['iifname { "' + interface + '", "' + interface_wc + '" }', 'jump VYOS_PBR_smoketest'],              ['meta l4proto udp', 'drop'],              ['tcp flags syn / syn,ack', 'meta mark set ' + mark_hex],              ['ct state new', 'tcp dport 22', 'ip saddr 198.51.100.0/24', 'ip ttl > 2', 'meta mark set ' + mark_hex], @@ -256,7 +258,7 @@ class TestPolicyRoute(VyOSUnitTestSHIM.TestCase):          # IPv6          nftables6_search = [ -            [f'iifname "{interface}"', 'jump VYOS_PBR6_smoketest'], +            [f'iifname "{interface_wc}"', 'jump VYOS_PBR6_smoketest'],              ['meta l4proto udp', 'drop'],              ['tcp flags syn / syn,ack', 'meta mark set ' + mark_hex],              ['ct state new', 'tcp dport 22', 'ip6 saddr 2001:db8::/64', 'ip6 hoplimit > 2', 'meta mark set ' + mark_hex], diff --git a/smoketest/scripts/cli/test_protocols_bgp.py b/smoketest/scripts/cli/test_protocols_bgp.py index f6eede87a..2fd5d0c9b 100755 --- a/smoketest/scripts/cli/test_protocols_bgp.py +++ b/smoketest/scripts/cli/test_protocols_bgp.py @@ -713,7 +713,6 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):          for prefix in listen_ranges:              self.assertIn(f' bgp listen range {prefix} peer-group {peer_group}', frrconfig) -      def test_bgp_07_l2vpn_evpn(self):          vnis = ['10010', '10020', '10030']          neighbors = ['192.0.2.10', '192.0.2.20', '192.0.2.30'] @@ -743,26 +742,6 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):              self.assertIn(f'   advertise-default-gw', vniconfig)              self.assertIn(f'   advertise-svi-ip', vniconfig) -    def test_bgp_08_zebra_route_map(self): -        # Implemented because of T3328 -        self.cli_set(base_path + ['route-map', route_map_in]) -        # commit changes -        self.cli_commit() - -        # Verify FRR configuration -        zebra_route_map = f'ip protocol bgp route-map {route_map_in}' -        frrconfig = self.getFRRconfig(zebra_route_map) -        self.assertIn(zebra_route_map, frrconfig) - -        # Remove the route-map again -        self.cli_delete(base_path + ['route-map']) -        # commit changes -        self.cli_commit() - -        # Verify FRR configuration -        frrconfig = self.getFRRconfig(zebra_route_map) -        self.assertNotIn(zebra_route_map, frrconfig) -      def test_bgp_09_distance_and_flowspec(self):          distance_external = '25'          distance_internal = '30' @@ -830,7 +809,6 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):              self.cli_set(vrf_base + ['table', table])              self.cli_set(vrf_base + ['protocols', 'bgp', 'system-as', ASN])              self.cli_set(vrf_base + ['protocols', 'bgp', 'parameters', 'router-id', router_id]) -            self.cli_set(vrf_base + ['protocols', 'bgp', 'route-map', route_map_in])              table = str(int(table) + 1000)              # import VRF routes do main RIB @@ -843,7 +821,6 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):          self.assertIn(f'router bgp {ASN}', frrconfig)          self.assertIn(f' address-family ipv6 unicast', frrconfig) -          for vrf in vrfs:              self.assertIn(f'  import vrf {vrf}', frrconfig) @@ -852,15 +829,6 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):              self.assertIn(f'router bgp {ASN} vrf {vrf}', frr_vrf_config)              self.assertIn(f' bgp router-id {router_id}', frr_vrf_config) -            # XXX: Currently this is not working as FRR() class does not support -            # route-maps for multiple vrfs because the modify_section() only works -            # on lines and not text blocks. -            # -            # vrfconfig = self.getFRRconfig(f'vrf {vrf}') -            # zebra_route_map = f' ip protocol bgp route-map {route_map_in}' -            # self.assertIn(zebra_route_map, vrfconfig) - -      def test_bgp_11_confederation(self):          router_id = '127.10.10.2'          confed_id = str(int(ASN) + 1) diff --git a/smoketest/scripts/cli/test_protocols_isis.py b/smoketest/scripts/cli/test_protocols_isis.py index d11d80a1f..f1a030e77 100755 --- a/smoketest/scripts/cli/test_protocols_isis.py +++ b/smoketest/scripts/cli/test_protocols_isis.py @@ -119,39 +119,6 @@ class TestProtocolsISIS(VyOSUnitTestSHIM.TestCase):          self.cli_delete(['vrf', 'name', vrf])          self.cli_delete(['interfaces', 'ethernet', vrf_iface, 'vrf']) -    def test_isis_03_zebra_route_map(self): -        # Implemented because of T3328 -        route_map = 'foo-isis-in' - -        self.cli_set(['policy', 'route-map', route_map, 'rule', '10', 'action', 'permit']) - -        self.isis_base_config() -        self.cli_set(base_path + ['redistribute', 'ipv4', 'connected', 'level-2', 'route-map', route_map]) -        self.cli_set(base_path + ['route-map', route_map]) -        self.cli_set(base_path + ['level', 'level-2']) - -        # commit changes -        self.cli_commit() - -        # Verify FRR configuration -        zebra_route_map = f'ip protocol isis route-map {route_map}' -        frrconfig = self.getFRRconfig(zebra_route_map, daemon='zebra') -        self.assertIn(zebra_route_map, frrconfig) - -        tmp = self.getFRRconfig(f'router isis {domain}', daemon='isisd') -        self.assertIn(' is-type level-2-only', tmp) - -        # Remove the route-map again -        self.cli_delete(base_path + ['route-map']) -        # commit changes -        self.cli_commit() - -        # Verify FRR configuration -        frrconfig = self.getFRRconfig(zebra_route_map, daemon='zebra') -        self.assertNotIn(zebra_route_map, frrconfig) - -        self.cli_delete(['policy', 'route-map', route_map]) -      def test_isis_04_default_information(self):          metric = '50'          route_map = 'default-foo-' @@ -293,7 +260,7 @@ class TestProtocolsISIS(VyOSUnitTestSHIM.TestCase):          self.cli_set(base_path + ['segment-routing', 'prefix', prefix_three, 'absolute', 'explicit-null'])          self.cli_set(base_path + ['segment-routing', 'prefix', prefix_four, 'absolute', 'value', prefix_four_value])          self.cli_set(base_path + ['segment-routing', 'prefix', prefix_four, 'absolute', 'no-php-flag']) -         +          # Commit all changes          self.cli_commit() @@ -308,5 +275,48 @@ class TestProtocolsISIS(VyOSUnitTestSHIM.TestCase):          self.assertIn(f' segment-routing prefix {prefix_three} absolute {prefix_three_value} explicit-null', tmp)          self.assertIn(f' segment-routing prefix {prefix_four} absolute {prefix_four_value} no-php-flag', tmp) +    def test_isis_08_ldp_sync(self): +        holddown = "500" +        interface = 'lo' + +        self.cli_set(base_path + ['net', net]) +        self.cli_set(base_path + ['interface', interface]) +        self.cli_set(base_path + ['ldp-sync', 'holddown', holddown]) + +        # Commit main ISIS changes +        self.cli_commit() + +        # Verify main ISIS changes +        tmp = self.getFRRconfig(f'router isis {domain}', daemon='isisd') +        self.assertIn(f' net {net}', tmp) +        self.assertIn(f' mpls ldp-sync', tmp) +        self.assertIn(f' mpls ldp-sync holddown {holddown}', tmp) + +        for interface in self._interfaces: +            self.cli_set(base_path + ['interface', interface, 'ldp-sync', 'holddown', holddown]) + +            # Commit interface changes for holddown +            self.cli_commit() + +            # Verify interface changes for holddown +            tmp = self.getFRRconfig(f'interface {interface}', daemon='isisd') +            self.assertIn(f'interface {interface}', tmp) +            self.assertIn(f' ip router isis {domain}', tmp) +            self.assertIn(f' ipv6 router isis {domain}', tmp) +            self.assertIn(f' isis mpls ldp-sync holddown {holddown}', tmp) + +        for interface in self._interfaces: +            self.cli_set(base_path + ['interface', interface, 'ldp-sync', 'disable']) + +            # Commit interface changes for disable +            self.cli_commit() + +            # Verify interface changes for disable +            tmp = self.getFRRconfig(f'interface {interface}', daemon='isisd') +            self.assertIn(f'interface {interface}', tmp) +            self.assertIn(f' ip router isis {domain}', tmp) +            self.assertIn(f' ipv6 router isis {domain}', tmp) +            self.assertIn(f' no isis mpls ldp-sync', tmp) +  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 581959b15..6fe6dd979 100755 --- a/smoketest/scripts/cli/test_protocols_ospf.py +++ b/smoketest/scripts/cli/test_protocols_ospf.py @@ -300,26 +300,6 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase):              self.assertIn(f' no ip ospf passive', config)              self.assertIn(f' bandwidth {bandwidth}', config) -    def test_ospf_10_zebra_route_map(self): -        # Implemented because of T3328 -        self.cli_set(base_path + ['route-map', route_map]) -        # commit changes -        self.cli_commit() - -        # Verify FRR configuration -        zebra_route_map = f'ip protocol ospf route-map {route_map}' -        frrconfig = self.getFRRconfig(zebra_route_map) -        self.assertIn(zebra_route_map, frrconfig) - -        # Remove the route-map again -        self.cli_delete(base_path + ['route-map']) -        # commit changes -        self.cli_commit() - -        # Verify FRR configuration -        frrconfig = self.getFRRconfig(zebra_route_map) -        self.assertNotIn(zebra_route_map, frrconfig) -      def test_ospf_11_interface_area(self):          area = '0'          interfaces = Section.interfaces('ethernet') @@ -434,6 +414,47 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase):          self.assertIn(f' segment-routing prefix {prefix_one} index {prefix_one_value} explicit-null', frrconfig)          self.assertIn(f' segment-routing prefix {prefix_two} index {prefix_two_value} no-php-flag', frrconfig) +    def test_ospf_15_ldp_sync(self): +        holddown = "500" +        interface = 'lo' +        interfaces = Section.interfaces('ethernet') + +        self.cli_set(base_path + ['interface', interface]) +        self.cli_set(base_path + ['ldp-sync', 'holddown', holddown]) + +        # Commit main OSPF changes +        self.cli_commit() + +        # Verify main OSPF changes +        frrconfig = self.getFRRconfig('router ospf') +        self.assertIn(f'router ospf', frrconfig) +        self.assertIn(f' timers throttle spf 200 1000 10000', frrconfig) +        self.assertIn(f' mpls ldp-sync holddown {holddown}', frrconfig) + +        for interface in interfaces: +            self.cli_set(base_path + ['interface', interface, 'ldp-sync', 'holddown', holddown]) + +            # Commit interface changes for holddown +            self.cli_commit() + +            # Verify interface changes for holddown +            config = self.getFRRconfig(f'interface {interface}') +            self.assertIn(f'interface {interface}', config) +            self.assertIn(f' ip ospf dead-interval 40', config) +            self.assertIn(f' ip ospf mpls ldp-sync', config) +            self.assertIn(f' ip ospf mpls ldp-sync holddown {holddown}', config) + +        for interface in interfaces: +            self.cli_set(base_path + ['interface', interface, 'ldp-sync', 'disable']) + +            # Commit interface changes for disable +            self.cli_commit() + +            # Verify interface changes for disable +            config = self.getFRRconfig(f'interface {interface}') +            self.assertIn(f'interface {interface}', config) +            self.assertIn(f' ip ospf dead-interval 40', config) +            self.assertIn(f' no ip ospf mpls ldp-sync', config)  if __name__ == '__main__':      unittest.main(verbosity=2) diff --git a/smoketest/scripts/cli/test_protocols_static.py b/smoketest/scripts/cli/test_protocols_static.py index 19efe7786..bc023f3f2 100755 --- a/smoketest/scripts/cli/test_protocols_static.py +++ b/smoketest/scripts/cli/test_protocols_static.py @@ -433,30 +433,5 @@ class TestProtocolsStatic(VyOSUnitTestSHIM.TestCase):                      self.assertIn(tmp, frrconfig) -    def test_04_static_zebra_route_map(self): -        # Implemented because of T3328 -        route_map = 'foo-static-in' -        self.cli_set(['policy', 'route-map', route_map, 'rule', '10', 'action', 'permit']) - -        self.cli_set(base_path + ['route-map', route_map]) -        # commit changes -        self.cli_commit() - -        # Verify FRR configuration -        zebra_route_map = f'ip protocol static route-map {route_map}' -        frrconfig = self.getFRRconfig(zebra_route_map) -        self.assertIn(zebra_route_map, frrconfig) - -        # Remove the route-map again -        self.cli_delete(base_path + ['route-map']) -        # commit changes -        self.cli_commit() - -        # Verify FRR configuration -        frrconfig = self.getFRRconfig(zebra_route_map) -        self.assertNotIn(zebra_route_map, frrconfig) - -        self.cli_delete(['policy', 'route-map', route_map]) -  if __name__ == '__main__':      unittest.main(verbosity=2) diff --git a/smoketest/scripts/cli/test_system_ip.py b/smoketest/scripts/cli/test_system_ip.py index f71ef5b3f..e7f7e3345 100755 --- a/smoketest/scripts/cli/test_system_ip.py +++ b/smoketest/scripts/cli/test_system_ip.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 @@ -17,6 +17,7 @@  import unittest  from base_vyostest_shim import VyOSUnitTestSHIM +from vyos.configsession import ConfigSessionError  from vyos.util import read_file  base_path = ['system', 'ip'] @@ -82,5 +83,31 @@ class TestSystemIP(VyOSUnitTestSHIM.TestCase):              self.assertEqual(read_file(gc_thresh2), str(size // 2))              self.assertEqual(read_file(gc_thresh1), str(size // 8)) +    def test_system_ip_protocol_route_map(self): +        protocols = ['any', 'babel', 'bgp', 'connected', 'eigrp', 'isis', +                     'kernel', 'ospf', 'rip', 'static', 'table'] + +        for protocol in protocols: +            self.cli_set(['policy', 'route-map', f'route-map-{protocol}', 'rule', '10', 'action', 'permit']) +            self.cli_set(base_path + ['protocol', protocol, 'route-map', f'route-map-{protocol}']) + +        self.cli_commit() + +        # Verify route-map properly applied to FRR +        frrconfig = self.getFRRconfig('ip protocol', end='', daemon='zebra') +        for protocol in protocols: +            self.assertIn(f'ip protocol {protocol} route-map route-map-{protocol}', frrconfig) + +    def test_system_ip_protocol_non_existing_route_map(self): +        non_existing = 'non-existing' +        self.cli_set(base_path + ['protocol', 'static', 'route-map', non_existing]) + +        # VRF does yet not exist - an error must be thrown +        with self.assertRaises(ConfigSessionError): +            self.cli_commit() +        self.cli_set(['policy', 'route-map', non_existing, 'rule', '10', 'action', 'deny']) +        # Commit again +        self.cli_commit() +  if __name__ == '__main__':      unittest.main(verbosity=2) diff --git a/smoketest/scripts/cli/test_system_ipv6.py b/smoketest/scripts/cli/test_system_ipv6.py index c8aea9100..e91b924fc 100755 --- a/smoketest/scripts/cli/test_system_ipv6.py +++ b/smoketest/scripts/cli/test_system_ipv6.py @@ -1,6 +1,6 @@  #!/usr/bin/env python3  # -# Copyright (C) 2021-2022 VyOS maintainers and contributors +# Copyright (C) 2021-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 @@ -18,6 +18,7 @@ import unittest  from base_vyostest_shim import VyOSUnitTestSHIM +from vyos.configsession import ConfigSessionError  from vyos.template import is_ipv4  from vyos.util import read_file  from vyos.util import get_interface_config @@ -88,5 +89,36 @@ class TestSystemIPv6(VyOSUnitTestSHIM.TestCase):              self.assertEqual(read_file(gc_thresh2), str(size // 2))              self.assertEqual(read_file(gc_thresh1), str(size // 8)) +    def test_system_ipv6_protocol_route_map(self): +        protocols = ['any', 'babel', 'bgp', 'connected', 'isis', +                     'kernel', 'ospfv3', 'ripng', 'static', 'table'] + +        for protocol in protocols: +            route_map = 'route-map-' + protocol.replace('ospfv3', 'ospf6') + +            self.cli_set(['policy', 'route-map', route_map, 'rule', '10', 'action', 'permit']) +            self.cli_set(base_path + ['protocol', protocol, 'route-map', route_map]) + +        self.cli_commit() + +        # Verify route-map properly applied to FRR +        frrconfig = self.getFRRconfig('ipv6 protocol', end='', daemon='zebra') +        for protocol in protocols: +            # VyOS and FRR use a different name for OSPFv3 (IPv6) +            if protocol == 'ospfv3': +                protocol = 'ospf6' +            self.assertIn(f'ipv6 protocol {protocol} route-map route-map-{protocol}', frrconfig) + +    def test_system_ipv6_protocol_non_existing_route_map(self): +        non_existing = 'non-existing6' +        self.cli_set(base_path + ['protocol', 'static', 'route-map', non_existing]) + +        # VRF does yet not exist - an error must be thrown +        with self.assertRaises(ConfigSessionError): +            self.cli_commit() +        self.cli_set(['policy', 'route-map', non_existing, 'rule', '10', 'action', 'deny']) +        # Commit again +        self.cli_commit() +  if __name__ == '__main__':      unittest.main(verbosity=2) diff --git a/smoketest/scripts/cli/test_system_login.py b/smoketest/scripts/cli/test_system_login.py index 6006fe0f6..a1d2ba2ad 100755 --- a/smoketest/scripts/cli/test_system_login.py +++ b/smoketest/scripts/cli/test_system_login.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 @@ -264,5 +264,26 @@ class TestSystemLogin(VyOSUnitTestSHIM.TestCase):          tmp = re.findall(r'group:\s+mapname\s+files', nsswitch_conf)          self.assertTrue(tmp) +    def test_system_login_max_login_session(self): +        max_logins = '2' +        timeout = '600' + +        self.cli_set(base_path + ['max-login-session', max_logins]) + +        # 'max-login-session' must be only with 'timeout' option +        with self.assertRaises(ConfigSessionError): +            self.cli_commit() + +        self.cli_set(base_path + ['timeout', timeout]) + +        self.cli_commit() + +        security_limits = read_file('/etc/security/limits.d/10-vyos.conf') +        self.assertIn(f'* - maxsyslogins {max_logins}', security_limits) + +        self.cli_delete(base_path + ['timeout']) +        self.cli_delete(base_path + ['max-login-session']) + +  if __name__ == '__main__':      unittest.main(verbosity=2) diff --git a/smoketest/scripts/cli/test_system_sflow.py b/smoketest/scripts/cli/test_system_sflow.py index fef88b56a..1aec050a4 100755 --- a/smoketest/scripts/cli/test_system_sflow.py +++ b/smoketest/scripts/cli/test_system_sflow.py @@ -91,6 +91,7 @@ class TestSystemFlowAccounting(VyOSUnitTestSHIM.TestCase):          self.assertIn(f'collector {{ ip = {server} udpport = {port} }}', hsflowd)          self.assertIn(f'collector {{ ip = {local_server} udpport = {default_port} }}', hsflowd)          self.assertIn(f'dropmon {{ limit={mon_limit} start=on sw=on hw=off }}', hsflowd) +        self.assertIn('dbus { }', hsflowd)          for interface in Section.interfaces('ethernet'):              self.assertIn(f'pcap {{ dev={interface} }}', hsflowd) diff --git a/smoketest/scripts/cli/test_vrf.py b/smoketest/scripts/cli/test_vrf.py index 176c095fb..8016c0105 100755 --- a/smoketest/scripts/cli/test_vrf.py +++ b/smoketest/scripts/cli/test_vrf.py @@ -1,6 +1,6 @@  #!/usr/bin/env python3  # -# Copyright (C) 2020-2022 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 @@ -33,6 +33,8 @@ from vyos.validate import is_intf_addr_assigned  base_path = ['vrf']  vrfs = ['red', 'green', 'blue', 'foo-bar', 'baz_foo'] +v4_protocols = ['any', 'babel', 'bgp', 'connected', 'eigrp', 'isis', 'kernel', 'ospf', 'rip', 'static', 'table'] +v6_protocols = ['any', 'babel', 'bgp', 'connected', 'isis', 'kernel', 'ospfv3', 'ripng', 'static', 'table']  class VRFTest(VyOSUnitTestSHIM.TestCase):      _interfaces = [] @@ -291,5 +293,81 @@ class VRFTest(VyOSUnitTestSHIM.TestCase):              self.assertEqual(read_file(f'/proc/sys/net/ipv4/conf/{vrf}/forwarding'), '0')              self.assertEqual(read_file(f'/proc/sys/net/ipv6/conf/{vrf}/forwarding'), '0') +    def test_vrf_ip_protocol_route_map(self): +        table = '6000' + +        for vrf in vrfs: +            base = base_path + ['name', vrf] +            self.cli_set(base + ['table', table]) + +            for protocol in v4_protocols: +                self.cli_set(['policy', 'route-map', f'route-map-{vrf}-{protocol}', 'rule', '10', 'action', 'permit']) +                self.cli_set(base + ['ip', 'protocol', protocol, 'route-map', f'route-map-{vrf}-{protocol}']) + +            table = str(int(table) + 1) + +        self.cli_commit() + +        # Verify route-map properly applied to FRR +        for vrf in vrfs: +            frrconfig = self.getFRRconfig(f'vrf {vrf}', daemon='zebra') +            self.assertIn(f'vrf {vrf}', frrconfig) +            for protocol in v4_protocols: +                self.assertIn(f' ip protocol {protocol} route-map route-map-{vrf}-{protocol}', frrconfig) + +    def test_vrf_ip_ipv6_protocol_non_existing_route_map(self): +        table = '6100' +        non_existing = 'non-existing' + +        for vrf in vrfs: +            base = base_path + ['name', vrf] +            self.cli_set(base + ['table', table]) +            for protocol in v4_protocols: +                self.cli_set(base + ['ip', 'protocol', protocol, 'route-map', f'v4-{non_existing}']) +            for protocol in v6_protocols: +                self.cli_set(base + ['ipv6', 'protocol', protocol, 'route-map', f'v6-{non_existing}']) + +            table = str(int(table) + 1) + +        # Both v4 and v6 route-maps do not exist yet +        with self.assertRaises(ConfigSessionError): +            self.cli_commit() +        self.cli_set(['policy', 'route-map', f'v4-{non_existing}', 'rule', '10', 'action', 'deny']) + +        # v6 route-map does not exist yet +        with self.assertRaises(ConfigSessionError): +            self.cli_commit() +        self.cli_set(['policy', 'route-map', f'v6-{non_existing}', 'rule', '10', 'action', 'deny']) + +        # Commit again +        self.cli_commit() + +    def test_vrf_ipv6_protocol_route_map(self): +        table = '6200' + +        for vrf in vrfs: +            base = base_path + ['name', vrf] +            self.cli_set(base + ['table', table]) + +            for protocol in v6_protocols: +                route_map = f'route-map-{vrf}-{protocol.replace("ospfv3", "ospf6")}' +                self.cli_set(['policy', 'route-map', route_map, 'rule', '10', 'action', 'permit']) +                self.cli_set(base + ['ipv6', 'protocol', protocol, 'route-map', route_map]) + +            table = str(int(table) + 1) + +        self.cli_commit() + +        # Verify route-map properly applied to FRR +        for vrf in vrfs: +            frrconfig = self.getFRRconfig(f'vrf {vrf}', daemon='zebra') +            self.assertIn(f'vrf {vrf}', frrconfig) +            for protocol in v6_protocols: +                # VyOS and FRR use a different name for OSPFv3 (IPv6) +                if protocol == 'ospfv3': +                    protocol = 'ospf6' +                route_map = f'route-map-{vrf}-{protocol}' +                self.assertIn(f' ipv6 protocol {protocol} route-map {route_map}', frrconfig) +  if __name__ == '__main__':      unittest.main(verbosity=2) diff --git a/src/completion/list_ipsec_profile_tunnels.py b/src/completion/list_ipsec_profile_tunnels.py new file mode 100644 index 000000000..df6c52f6d --- /dev/null +++ b/src/completion/list_ipsec_profile_tunnels.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python3 +# +# 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 +# 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 os +import sys +import argparse + +from vyos.config import Config +from vyos.util import dict_search + +def get_tunnels_from_ipsecprofile(profile): +    config = Config() +    base = ['vpn', 'ipsec', 'profile', profile, 'bind'] +    profile_conf = config.get_config_dict(base, effective=True, key_mangling=('-', '_')) +    tunnels = [] + +    try: +        for tunnel in (dict_search('bind.tunnel', profile_conf) or []): +            tunnels.append(tunnel) +    except: +        pass + +    return tunnels + +if __name__ == "__main__": +    parser = argparse.ArgumentParser() +    parser.add_argument("-p", "--profile", type=str, help="List tunnels per profile") +    args = parser.parse_args() + +    tunnels = [] + +    tunnels = get_tunnels_from_ipsecprofile(args.profile) + +    print(" ".join(tunnels)) + diff --git a/src/conf_mode/container.py b/src/conf_mode/container.py index bf83416b2..aceb27fb0 100755 --- a/src/conf_mode/container.py +++ b/src/conf_mode/container.py @@ -16,6 +16,7 @@  import os +from hashlib import sha256  from ipaddress import ip_address  from ipaddress import ip_network  from json import dumps as json_write @@ -25,9 +26,10 @@ from vyos.config import Config  from vyos.configdict import dict_merge  from vyos.configdict import node_changed  from vyos.configdict import is_node_changed +from vyos.configverify import verify_vrf +from vyos.ifconfig import Interface  from vyos.util import call  from vyos.util import cmd -from vyos.util import dict_search  from vyos.util import run  from vyos.util import rc_cmd  from vyos.util import write_file @@ -166,21 +168,29 @@ def verify(container):                      raise ConfigError(f'Container network "{network_name}" does not exist!')                  if 'address' in container_config['network'][network_name]: -                    address = container_config['network'][network_name]['address'] -                    network = None -                    if is_ipv4(address): -                        network = [x for x in container['network'][network_name]['prefix'] if is_ipv4(x)][0] -                    elif is_ipv6(address): -                        network = [x for x in container['network'][network_name]['prefix'] if is_ipv6(x)][0] - -                    # Specified container IP address must belong to network prefix -                    if ip_address(address) not in ip_network(network): -                        raise ConfigError(f'Used container address "{address}" not in network "{network}"!') - -                    # We can not use the first IP address of a network prefix as this is used by podman -                    if ip_address(address) == ip_network(network)[1]: -                        raise ConfigError(f'IP address "{address}" can not be used for a container, '\ -                                          'reserved for the container engine!') +                    cnt_ipv4 = 0 +                    cnt_ipv6 = 0 +                    for address in container_config['network'][network_name]['address']: +                        network = None +                        if is_ipv4(address): +                            network = [x for x in container['network'][network_name]['prefix'] if is_ipv4(x)][0] +                            cnt_ipv4 += 1 +                        elif is_ipv6(address): +                            network = [x for x in container['network'][network_name]['prefix'] if is_ipv6(x)][0] +                            cnt_ipv6 += 1 + +                        # Specified container IP address must belong to network prefix +                        if ip_address(address) not in ip_network(network): +                            raise ConfigError(f'Used container address "{address}" not in network "{network}"!') + +                        # We can not use the first IP address of a network prefix as this is used by podman +                        if ip_address(address) == ip_network(network)[1]: +                            raise ConfigError(f'IP address "{address}" can not be used for a container, '\ +                                              'reserved for the container engine!') + +                    if cnt_ipv4 > 1 or cnt_ipv6 > 1: +                        raise ConfigError(f'Only one IP address per address family can be used for '\ +                                          f'container "{name}". {cnt_ipv4} IPv4 and {cnt_ipv6} IPv6 address(es)!')              if 'device' in container_config:                  for dev, dev_config in container_config['device'].items(): @@ -242,6 +252,8 @@ def verify(container):              if v6_prefix > 1:                  raise ConfigError(f'Only one IPv6 prefix can be defined for network "{network}"!') +            # Verify VRF exists +            verify_vrf(network_config)      # A network attached to a container can not be deleted      if {'network_remove', 'name'} <= set(container): @@ -250,9 +262,11 @@ def verify(container):                  if 'network' in container_config and network in container_config['network']:                      raise ConfigError(f'Can not remove network "{network}", used by container "{container}"!') -    if 'registry' in container and 'authentication' in container['registry']: -        for registry, registry_config in container['registry']['authentication'].items(): -            if not {'username', 'password'} <= set(registry_config): +    if 'registry' in container: +        for registry, registry_config in container['registry'].items(): +            if 'authentication' not in registry_config: +                continue +            if not {'username', 'password'} <= set(registry_config['authentication']):                  raise ConfigError('If registry username or or password is defined, so must be the other!')      return None @@ -338,9 +352,13 @@ def generate_run_arguments(name, container_config):      ip_param = ''      networks = ",".join(container_config['network'])      for network in container_config['network']: -        if 'address' in container_config['network'][network]: -            address = container_config['network'][network]['address'] -            ip_param = f'--ip {address}' +        if 'address' not in container_config['network'][network]: +            continue +        for address in container_config['network'][network]['address']: +            if is_ipv6(address): +                ip_param += f' --ip6 {address}' +            else: +                ip_param += f' --ip {address}'      return f'{container_base_cmd} --net {networks} {ip_param} {entrypoint} {image} {command} {command_arguments}'.strip() @@ -355,33 +373,26 @@ def generate(container):      if 'network' in container:          for network, network_config in container['network'].items():              tmp = { -                'cniVersion' : '0.4.0', -                'name' : network, -                'plugins' : [{ -                    'type': 'bridge', -                    'bridge': f'cni-{network}', -                    'isGateway': True, -                    'ipMasq': False, -                    'hairpinMode': False, -                    'ipam' : { -                        'type': 'host-local', -                        'routes': [], -                        'ranges' : [], -                    }, -                }] +                'name': network, +                'id' : sha256(f'{network}'.encode()).hexdigest(), +                'driver': 'bridge', +                'network_interface': f'pod-{network}', +                'subnets': [], +                'ipv6_enabled': False, +                'internal': False, +                'dns_enabled': True, +                'ipam_options': { +                    'driver': 'host-local' +                }              } -              for prefix in network_config['prefix']: -                net = [{'gateway' : inc_ip(prefix, 1), 'subnet' : prefix}] -                tmp['plugins'][0]['ipam']['ranges'].append(net) +                net = {'subnet' : prefix, 'gateway' : inc_ip(prefix, 1)} +                tmp['subnets'].append(net) -                # install per address-family default orutes -                default_route = '0.0.0.0/0'                  if is_ipv6(prefix): -                    default_route = '::/0' -                tmp['plugins'][0]['ipam']['routes'].append({'dst': default_route}) +                    tmp['ipv6_enabled'] = True -            write_file(f'/etc/cni/net.d/{network}.conflist', json_write(tmp, indent=2)) +            write_file(f'/etc/containers/networks/{network}.json', json_write(tmp, indent=2))      if 'registry' in container:          cmd = f'podman logout --all' @@ -432,10 +443,7 @@ def apply(container):      # Delete old networks if needed      if 'network_remove' in container:          for network in container['network_remove']: -            call(f'podman network rm {network}') -            tmp = f'/etc/cni/net.d/{network}.conflist' -            if os.path.exists(tmp): -                os.unlink(tmp) +            call(f'podman network rm {network} >/dev/null 2>&1')      # Add container      disabled_new = False @@ -459,12 +467,26 @@ def apply(container):                          os.unlink(file_path)                  continue -            if name in dict_search('container_restart', container): +            if 'container_restart' in container and name in container['container_restart']:                  cmd(f'systemctl restart vyos-container-{name}.service')      if disabled_new:          call('systemctl daemon-reload') +    # Start network and assign it to given VRF if requested. this can only be done +    # after the containers got started as the podman network interface will +    # only be enabled by the first container and yet I do not know how to enable +    # the network interface in advance +    if 'network' in container: +        for network, network_config in container['network'].items(): +            network_name = f'pod-{network}' +            # T5147: Networks are started only as soon as there is a consumer. +            # If only a network is created in the first place, no need to assign +            # it to a VRF as there's no consumer, yet. +            if os.path.exists(f'/sys/class/net/{network_name}'): +                tmp = Interface(network_name) +                tmp.set_vrf(network_config.get('vrf', '')) +      return None  if __name__ == '__main__': diff --git a/src/conf_mode/firewall.py b/src/conf_mode/firewall.py index c41a442df..190587980 100755 --- a/src/conf_mode/firewall.py +++ b/src/conf_mode/firewall.py @@ -282,6 +282,9 @@ def verify_rule(firewall, rule_conf, ipv6):                  if rule_conf['protocol'] not in ['tcp', 'udp', 'tcp_udp']:                      raise ConfigError('Protocol must be tcp, udp, or tcp_udp when specifying a port or port-group') +            if 'port' in side_conf and dict_search_args(side_conf, 'group', 'port_group'): +                raise ConfigError(f'{side} port-group and port cannot both be defined') +      if 'log_options' in rule_conf:          if 'log' not in rule_conf or 'enable' not in rule_conf['log']:              raise ConfigError('log-options defined, but log is not enable') diff --git a/src/conf_mode/https.py b/src/conf_mode/https.py index ce5e63928..b0c38e8d3 100755 --- a/src/conf_mode/https.py +++ b/src/conf_mode/https.py @@ -159,6 +159,8 @@ def generate(https):              server_block['port'] = data.get('listen-port', '443')              name = data.get('server-name', ['_'])              server_block['name'] = name +            allow_client = data.get('allow-client', {}) +            server_block['allow_client'] = allow_client.get('address', [])              server_block_list.append(server_block)      # get certificate data diff --git a/src/conf_mode/interfaces-openvpn.py b/src/conf_mode/interfaces-openvpn.py index 13d84a6fe..6f227b0d1 100755 --- a/src/conf_mode/interfaces-openvpn.py +++ b/src/conf_mode/interfaces-openvpn.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 @@ -597,7 +597,7 @@ def generate_pki_files(openvpn):  def generate(openvpn):      interface = openvpn['ifname']      directory = os.path.dirname(cfg_file.format(**openvpn)) -    plugin_dir = '/usr/lib/openvpn' +    openvpn['plugin_dir'] = '/usr/lib/openvpn'      # create base config directory on demand      makedir(directory, user, group)      # enforce proper permissions on /run/openvpn diff --git a/src/conf_mode/protocols_bgp.py b/src/conf_mode/protocols_bgp.py index cf553f0e8..66505e58d 100755 --- a/src/conf_mode/protocols_bgp.py +++ b/src/conf_mode/protocols_bgp.py @@ -484,26 +484,15 @@ def generate(bgp):      if not bgp or 'deleted' in bgp:          return None -    bgp['protocol'] = 'bgp' # required for frr/vrf.route-map.frr.j2 -    bgp['frr_zebra_config'] = render_to_string('frr/vrf.route-map.frr.j2', bgp)      bgp['frr_bgpd_config']  = render_to_string('frr/bgpd.frr.j2', bgp) -      return None  def apply(bgp):      bgp_daemon = 'bgpd' -    zebra_daemon = 'zebra'      # Save original configuration prior to starting any commit actions      frr_cfg = frr.FRRConfig() -    # The route-map used for the FIB (zebra) is part of the zebra daemon -    frr_cfg.load_configuration(zebra_daemon) -    frr_cfg.modify_section(r'(\s+)?ip protocol bgp route-map [-a-zA-Z0-9.]+', stop_pattern='(\s|!)') -    if 'frr_zebra_config' in bgp: -        frr_cfg.add_before(frr.default_add_before, bgp['frr_zebra_config']) -    frr_cfg.commit_configuration(zebra_daemon) -      # Generate empty helper string which can be ammended to FRR commands, it      # will be either empty (default VRF) or contain the "vrf <name" statement      vrf = '' diff --git a/src/conf_mode/protocols_eigrp.py b/src/conf_mode/protocols_eigrp.py index c1a1a45e1..609b39065 100755 --- a/src/conf_mode/protocols_eigrp.py +++ b/src/conf_mode/protocols_eigrp.py @@ -69,8 +69,6 @@ def get_config(config=None):      # Merge policy dict into "regular" config dict      eigrp = dict_merge(tmp, eigrp) -    import pprint -    pprint.pprint(eigrp)      return eigrp  def verify(eigrp): @@ -80,24 +78,14 @@ def generate(eigrp):      if not eigrp or 'deleted' in eigrp:          return None -    eigrp['protocol'] = 'eigrp' # required for frr/vrf.route-map.frr.j2 -    eigrp['frr_zebra_config'] = render_to_string('frr/vrf.route-map.frr.j2', eigrp)      eigrp['frr_eigrpd_config']  = render_to_string('frr/eigrpd.frr.j2', eigrp)  def apply(eigrp):      eigrp_daemon = 'eigrpd' -    zebra_daemon = 'zebra'      # Save original configuration prior to starting any commit actions      frr_cfg = frr.FRRConfig() -    # The route-map used for the FIB (zebra) is part of the zebra daemon -    frr_cfg.load_configuration(zebra_daemon) -    frr_cfg.modify_section(r'(\s+)?ip protocol eigrp route-map [-a-zA-Z0-9.]+', stop_pattern='(\s|!)') -    if 'frr_zebra_config' in eigrp: -        frr_cfg.add_before(frr.default_add_before, eigrp['frr_zebra_config']) -    frr_cfg.commit_configuration(zebra_daemon) -      # Generate empty helper string which can be ammended to FRR commands, it      # will be either empty (default VRF) or contain the "vrf <name" statement      vrf = '' diff --git a/src/conf_mode/protocols_isis.py b/src/conf_mode/protocols_isis.py index cb8ea3be4..af2937db8 100755 --- a/src/conf_mode/protocols_isis.py +++ b/src/conf_mode/protocols_isis.py @@ -203,7 +203,7 @@ def verify(isis):          if list(set(global_range) & set(local_range)):              raise ConfigError(f'Segment-Routing Global Block ({g_low_label_value}/{g_high_label_value}) '\                                f'conflicts with Local Block ({l_low_label_value}/{l_high_label_value})!') -         +      # Check for a blank or invalid value per prefix      if dict_search('segment_routing.prefix', isis):          for prefix, prefix_config in isis['segment_routing']['prefix'].items(): @@ -218,7 +218,7 @@ def verify(isis):      if dict_search('segment_routing.prefix', isis):          for prefix, prefix_config in isis['segment_routing']['prefix'].items():              if 'absolute' in prefix_config: -                if ("explicit_null" in prefix_config['absolute']) and ("no_php_flag" in prefix_config['absolute']):  +                if ("explicit_null" in prefix_config['absolute']) and ("no_php_flag" in prefix_config['absolute']):                      raise ConfigError(f'Segment routing prefix {prefix} cannot have both explicit-null '\                                        f'and no-php-flag configured at the same time.')              elif 'index' in prefix_config: @@ -232,25 +232,15 @@ def generate(isis):      if not isis or 'deleted' in isis:          return None -    isis['protocol'] = 'isis' # required for frr/vrf.route-map.frr.j2 -    isis['frr_zebra_config'] = render_to_string('frr/vrf.route-map.frr.j2', isis)      isis['frr_isisd_config'] = render_to_string('frr/isisd.frr.j2', isis)      return None  def apply(isis):      isis_daemon = 'isisd' -    zebra_daemon = 'zebra'      # Save original configuration prior to starting any commit actions      frr_cfg = frr.FRRConfig() -    # The route-map used for the FIB (zebra) is part of the zebra daemon -    frr_cfg.load_configuration(zebra_daemon) -    frr_cfg.modify_section('(\s+)?ip protocol isis route-map [-a-zA-Z0-9.]+', stop_pattern='(\s|!)') -    if 'frr_zebra_config' in isis: -        frr_cfg.add_before(frr.default_add_before, isis['frr_zebra_config']) -    frr_cfg.commit_configuration(zebra_daemon) -      # Generate empty helper string which can be ammended to FRR commands, it      # will be either empty (default VRF) or contain the "vrf <name" statement      vrf = '' diff --git a/src/conf_mode/protocols_ospf.py b/src/conf_mode/protocols_ospf.py index eb64afa0c..fbb876123 100755 --- a/src/conf_mode/protocols_ospf.py +++ b/src/conf_mode/protocols_ospf.py @@ -256,25 +256,15 @@ def generate(ospf):      if not ospf or 'deleted' in ospf:          return None -    ospf['protocol'] = 'ospf' # required for frr/vrf.route-map.frr.j2 -    ospf['frr_zebra_config'] = render_to_string('frr/vrf.route-map.frr.j2', ospf)      ospf['frr_ospfd_config'] = render_to_string('frr/ospfd.frr.j2', ospf)      return None  def apply(ospf):      ospf_daemon = 'ospfd' -    zebra_daemon = 'zebra'      # Save original configuration prior to starting any commit actions      frr_cfg = frr.FRRConfig() -    # The route-map used for the FIB (zebra) is part of the zebra daemon -    frr_cfg.load_configuration(zebra_daemon) -    frr_cfg.modify_section('(\s+)?ip protocol ospf route-map [-a-zA-Z0-9.]+', stop_pattern='(\s|!)') -    if 'frr_zebra_config' in ospf: -        frr_cfg.add_before(frr.default_add_before, ospf['frr_zebra_config']) -    frr_cfg.commit_configuration(zebra_daemon) -      # Generate empty helper string which can be ammended to FRR commands, it      # will be either empty (default VRF) or contain the "vrf <name" statement      vrf = '' @@ -292,6 +282,7 @@ def apply(ospf):      if 'frr_ospfd_config' in ospf:          frr_cfg.add_before(frr.default_add_before, ospf['frr_ospfd_config']) +      frr_cfg.commit_configuration(ospf_daemon)      return None diff --git a/src/conf_mode/protocols_ospfv3.py b/src/conf_mode/protocols_ospfv3.py index 1e2c02d03..ee1fdd399 100755 --- a/src/conf_mode/protocols_ospfv3.py +++ b/src/conf_mode/protocols_ospfv3.py @@ -146,25 +146,15 @@ def generate(ospfv3):      if not ospfv3 or 'deleted' in ospfv3:          return None -    ospfv3['protocol'] = 'ospf6' # required for frr/vrf.route-map.v6.frr.j2 -    ospfv3['frr_zebra_config'] = render_to_string('frr/vrf.route-map.v6.frr.j2', ospfv3)      ospfv3['new_frr_config'] = render_to_string('frr/ospf6d.frr.j2', ospfv3)      return None  def apply(ospfv3):      ospf6_daemon = 'ospf6d' -    zebra_daemon = 'zebra'      # Save original configuration prior to starting any commit actions      frr_cfg = frr.FRRConfig() -    # The route-map used for the FIB (zebra) is part of the zebra daemon -    frr_cfg.load_configuration(zebra_daemon) -    frr_cfg.modify_section('(\s+)?ipv6 protocol ospf6 route-map [-a-zA-Z0-9.]+', stop_pattern='(\s|!)') -    if 'frr_zebra_config' in ospfv3: -        frr_cfg.add_before(frr.default_add_before, ospfv3['frr_zebra_config']) -    frr_cfg.commit_configuration(zebra_daemon) -      # Generate empty helper string which can be ammended to FRR commands, it      # will be either empty (default VRF) or contain the "vrf <name" statement      vrf = '' diff --git a/src/conf_mode/protocols_static.py b/src/conf_mode/protocols_static.py index 3e5ebb805..7b6150696 100755 --- a/src/conf_mode/protocols_static.py +++ b/src/conf_mode/protocols_static.py @@ -105,20 +105,14 @@ def generate(static):  def apply(static):      static_daemon = 'staticd' -    zebra_daemon = 'zebra'      # Save original configuration prior to starting any commit actions      frr_cfg = frr.FRRConfig() - -    # The route-map used for the FIB (zebra) is part of the zebra daemon -    frr_cfg.load_configuration(zebra_daemon) -    frr_cfg.modify_section(r'^ip protocol static route-map [-a-zA-Z0-9.]+', '') -    frr_cfg.commit_configuration(zebra_daemon)      frr_cfg.load_configuration(static_daemon)      if 'vrf' in static:          vrf = static['vrf'] -        frr_cfg.modify_section(f'^vrf {vrf}', stop_pattern='^exit', remove_stop_mark=True) +        frr_cfg.modify_section(f'^vrf {vrf}', stop_pattern='^exit-vrf', remove_stop_mark=True)      else:          frr_cfg.modify_section(r'^ip route .*')          frr_cfg.modify_section(r'^ipv6 route .*') diff --git a/src/conf_mode/service_monitoring_telegraf.py b/src/conf_mode/service_monitoring_telegraf.py index 363408679..47510ce80 100755 --- a/src/conf_mode/service_monitoring_telegraf.py +++ b/src/conf_mode/service_monitoring_telegraf.py @@ -1,6 +1,6 @@  #!/usr/bin/env python3  # -# Copyright (C) 2021-2022 VyOS maintainers and contributors +# Copyright (C) 2021-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 @@ -15,6 +15,7 @@  # along with this program.  If not, see <http://www.gnu.org/licenses/>.  import os +import socket  import json  from sys import exit @@ -57,6 +58,13 @@ def get_nft_filter_chains():      return chain_list +def get_hostname() -> str: +    try: +        hostname = socket.getfqdn() +    except socket.gaierror: +        hostname = socket.gethostname() +    return hostname +  def get_config(config=None):      if config:          conf = config @@ -79,6 +87,7 @@ def get_config(config=None):      monitoring = dict_merge(default_values, monitoring)      monitoring['custom_scripts_dir'] = custom_scripts_dir +    monitoring['hostname'] = get_hostname()      monitoring['interfaces_ethernet'] = Section.interfaces('ethernet', vlan=False)      monitoring['nft_chains'] = get_nft_filter_chains() diff --git a/src/conf_mode/system-ip.py b/src/conf_mode/system-ip.py index 0c5063ed3..95865c690 100755 --- a/src/conf_mode/system-ip.py +++ b/src/conf_mode/system-ip.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 @@ -18,12 +18,15 @@ from sys import exit  from vyos.config import Config  from vyos.configdict import dict_merge +from vyos.configverify import verify_route_map +from vyos.template import render_to_string  from vyos.util import call  from vyos.util import dict_search  from vyos.util import sysctl_write  from vyos.util import write_file  from vyos.xml import defaults  from vyos import ConfigError +from vyos import frr  from vyos import airbag  airbag.enable() @@ -40,13 +43,30 @@ def get_config(config=None):      default_values = defaults(base)      opt = dict_merge(default_values, opt) +    # When working with FRR we need to know the corresponding address-family +    opt['afi'] = 'ip' + +    # We also need the route-map information from the config +    # +    # XXX: one MUST always call this without the key_mangling() option! See +    # vyos.configverify.verify_common_route_maps() for more information. +    tmp = {'policy' : {'route-map' : conf.get_config_dict(['policy', 'route-map'], +                                                          get_first_key=True)}} +    # Merge policy dict into "regular" config dict +    opt = dict_merge(tmp, opt)      return opt  def verify(opt): -    pass +    if 'protocol' in opt: +        for protocol, protocol_options in opt['protocol'].items(): +            if 'route_map' in protocol_options: +                verify_route_map(protocol_options['route_map'], opt) +    return  def generate(opt): -    pass +    if 'protocol' in opt: +        opt['frr_zebra_config'] = render_to_string('frr/zebra.route-map.frr.j2', opt) +    return  def apply(opt):      # Apply ARP threshold values @@ -78,6 +98,18 @@ def apply(opt):      value = '1' if (tmp != None) else '0'      sysctl_write('net.ipv4.fib_multipath_hash_policy', value) +    if 'protocol' in opt: +        zebra_daemon = 'zebra' +        # Save original configuration prior to starting any commit actions +        frr_cfg = frr.FRRConfig() + +        # The route-map used for the FIB (zebra) is part of the zebra daemon +        frr_cfg.load_configuration(zebra_daemon) +        frr_cfg.modify_section(r'ip protocol \w+ route-map [-a-zA-Z0-9.]+', stop_pattern='(\s|!)') +        if 'frr_zebra_config' in opt: +            frr_cfg.add_before(frr.default_add_before, opt['frr_zebra_config']) +        frr_cfg.commit_configuration(zebra_daemon) +  if __name__ == '__main__':      try:          c = get_config() diff --git a/src/conf_mode/system-ipv6.py b/src/conf_mode/system-ipv6.py index 26aacf46b..b6d3a79c3 100755 --- a/src/conf_mode/system-ipv6.py +++ b/src/conf_mode/system-ipv6.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,11 +19,14 @@ import os  from sys import exit  from vyos.config import Config  from vyos.configdict import dict_merge +from vyos.configverify import verify_route_map +from vyos.template import render_to_string  from vyos.util import dict_search  from vyos.util import sysctl_write  from vyos.util import write_file  from vyos.xml import defaults  from vyos import ConfigError +from vyos import frr  from vyos import airbag  airbag.enable() @@ -41,13 +44,30 @@ def get_config(config=None):      default_values = defaults(base)      opt = dict_merge(default_values, opt) +    # When working with FRR we need to know the corresponding address-family +    opt['afi'] = 'ipv6' + +    # We also need the route-map information from the config +    # +    # XXX: one MUST always call this without the key_mangling() option! See +    # vyos.configverify.verify_common_route_maps() for more information. +    tmp = {'policy' : {'route-map' : conf.get_config_dict(['policy', 'route-map'], +                                                          get_first_key=True)}} +    # Merge policy dict into "regular" config dict +    opt = dict_merge(tmp, opt)      return opt  def verify(opt): -    pass +    if 'protocol' in opt: +        for protocol, protocol_options in opt['protocol'].items(): +            if 'route_map' in protocol_options: +                verify_route_map(protocol_options['route_map'], opt) +    return  def generate(opt): -    pass +    if 'protocol' in opt: +        opt['frr_zebra_config'] = render_to_string('frr/zebra.route-map.frr.j2', opt) +    return  def apply(opt):      # configure multipath @@ -78,6 +98,18 @@ def apply(opt):              if name == 'accept_dad':                  write_file(os.path.join(root, name), value) +    if 'protocol' in opt: +        zebra_daemon = 'zebra' +        # Save original configuration prior to starting any commit actions +        frr_cfg = frr.FRRConfig() + +        # The route-map used for the FIB (zebra) is part of the zebra daemon +        frr_cfg.load_configuration(zebra_daemon) +        frr_cfg.modify_section(r'ipv6 protocol \w+ route-map [-a-zA-Z0-9.]+', stop_pattern='(\s|!)') +        if 'frr_zebra_config' in opt: +            frr_cfg.add_before(frr.default_add_before, opt['frr_zebra_config']) +        frr_cfg.commit_configuration(zebra_daemon) +  if __name__ == '__main__':      try:          c = get_config() diff --git a/src/conf_mode/system-login.py b/src/conf_mode/system-login.py index d15fe399d..fbb013cf3 100755 --- a/src/conf_mode/system-login.py +++ b/src/conf_mode/system-login.py @@ -1,6 +1,6 @@  #!/usr/bin/env python3  # -# Copyright (C) 2020-2022 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 @@ -40,6 +40,7 @@ from vyos import airbag  airbag.enable()  autologout_file = "/etc/profile.d/autologout.sh" +limits_file = "/etc/security/limits.d/10-vyos.conf"  radius_config_file = "/etc/pam_radius_auth.conf"  # LOGIN_TIMEOUT from /etc/loign.defs minus 10 sec @@ -164,6 +165,9 @@ def verify(login):              if ipv6_count > 1:                  raise ConfigError('Only one IPv6 source-address can be set!') +    if 'max_login_session' in login and 'timeout' not in login: +        raise ConfigError('"login timeout" must be configured!') +      return None @@ -226,6 +230,14 @@ def generate(login):          if os.path.isfile(radius_config_file):              os.unlink(radius_config_file) +    # /etc/security/limits.d/10-vyos.conf +    if 'max_login_session' in login: +        render(limits_file, 'login/limits.j2', login, +                   permission=0o644, user='root', group='root') +    else: +        if os.path.isfile(limits_file): +            os.unlink(limits_file) +      if 'timeout' in login:          render(autologout_file, 'login/autologout.j2', login,                     permission=0o755, user='root', group='root') diff --git a/src/conf_mode/vpn_pptp.py b/src/conf_mode/vpn_pptp.py index 7550c411e..986a19972 100755 --- a/src/conf_mode/vpn_pptp.py +++ b/src/conf_mode/vpn_pptp.py @@ -1,6 +1,6 @@  #!/usr/bin/env python3  # -# Copyright (C) 2018-2020 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 @@ -44,6 +44,8 @@ default_pptp = {      'radius_nas_ip' : '',      'radius_source_address' : '',      'radius_shaper_attr' : '', +    'radius_shaper_enable': False, +    'radius_shaper_multiplier': '',      'radius_shaper_vendor': '',      'radius_dynamic_author' : '',      'chap_secrets_file': pptp_chap_secrets, # used in Jinja2 template @@ -183,15 +185,18 @@ def get_config(config=None):              pptp['radius_dynamic_author'] = dae +        # Rate limit +        if conf.exists(['rate-limit', 'attribute']): +            pptp['radius_shaper_attr'] = conf.return_value(['rate-limit', 'attribute']) +          if conf.exists(['rate-limit', 'enable']): -            pptp['radius_shaper_attr'] = 'Filter-Id' -            c_attr = ['rate-limit', 'enable', 'attribute'] -            if conf.exists(c_attr): -                pptp['radius_shaper_attr'] = conf.return_value(c_attr) - -            c_vendor = ['rate-limit', 'enable', 'vendor'] -            if conf.exists(c_vendor): -                pptp['radius_shaper_vendor'] = conf.return_value(c_vendor) +            pptp['radius_shaper_enable'] = True + +        if conf.exists(['rate-limit', 'multiplier']): +            pptp['radius_shaper_multiplier'] = conf.return_value(['rate-limit', 'multiplier']) + +        if conf.exists(['rate-limit', 'vendor']): +            pptp['radius_shaper_vendor'] = conf.return_value(['rate-limit', 'vendor'])      conf.set_level(base_path)      if conf.exists(['client-ip-pool']): diff --git a/src/conf_mode/vrf.py b/src/conf_mode/vrf.py index c17cca3bd..a7ef4cb5c 100755 --- a/src/conf_mode/vrf.py +++ b/src/conf_mode/vrf.py @@ -20,9 +20,12 @@ from sys import exit  from json import loads  from vyos.config import Config +from vyos.configdict import dict_merge  from vyos.configdict import node_changed +from vyos.configverify import verify_route_map  from vyos.ifconfig import Interface  from vyos.template import render +from vyos.template import render_to_string  from vyos.util import call  from vyos.util import cmd  from vyos.util import dict_search @@ -99,6 +102,14 @@ def get_config(config=None):          routes = vrf_routing(conf, name)          if routes: vrf['vrf_remove'][name]['route'] = routes +    # We also need the route-map information from the config +    # +    # XXX: one MUST always call this without the key_mangling() option! See +    # vyos.configverify.verify_common_route_maps() for more information. +    tmp = {'policy' : {'route-map' : conf.get_config_dict(['policy', 'route-map'], +                                                          get_first_key=True)}} +    # Merge policy dict into "regular" config dict +    vrf = dict_merge(tmp, vrf)      return vrf  def verify(vrf): @@ -116,35 +127,50 @@ def verify(vrf):          reserved_names = ["add", "all", "broadcast", "default", "delete", "dev", "get", "inet", "mtu", "link", "type",                            "vrf"]          table_ids = [] -        for name, config in vrf['name'].items(): +        for name, vrf_config in vrf['name'].items():              # Reserved VRF names              if name in reserved_names:                  raise ConfigError(f'VRF name "{name}" is reserved and connot be used!')              # table id is mandatory -            if 'table' not in config: +            if 'table' not in vrf_config:                  raise ConfigError(f'VRF "{name}" table id is mandatory!')              # routing table id can't be changed - OS restriction              if os.path.isdir(f'/sys/class/net/{name}'):                  tmp = str(dict_search('linkinfo.info_data.table', get_interface_config(name))) -                if tmp and tmp != config['table']: +                if tmp and tmp != vrf_config['table']:                      raise ConfigError(f'VRF "{name}" table id modification not possible!')              # VRf routing table ID must be unique on the system -            if config['table'] in table_ids: +            if vrf_config['table'] in table_ids:                  raise ConfigError(f'VRF "{name}" table id is not unique!') -            table_ids.append(config['table']) +            table_ids.append(vrf_config['table']) + +            tmp = dict_search('ip.protocol', vrf_config) +            if tmp != None: +                for protocol, protocol_options in tmp.items(): +                    if 'route_map' in protocol_options: +                        verify_route_map(protocol_options['route_map'], vrf) + +            tmp = dict_search('ipv6.protocol', vrf_config) +            if tmp != None: +                for protocol, protocol_options in tmp.items(): +                    if 'route_map' in protocol_options: +                        verify_route_map(protocol_options['route_map'], vrf)      return None  def generate(vrf): +    # Render iproute2 VR helper names      render(config_file, 'iproute2/vrf.conf.j2', vrf)      # Render nftables zones config      render(nft_vrf_config, 'firewall/nftables-vrf-zones.j2', vrf) -    return None +    # Render VRF Kernel/Zebra route-map filters +    vrf['frr_zebra_config'] = render_to_string('frr/zebra.vrf.route-map.frr.j2', vrf) +    return None  def apply(vrf):      # Documentation @@ -249,6 +275,17 @@ def apply(vrf):              nft_add_element = f'add element inet vrf_zones ct_iface_map {{ "{name}" : {table} }}'              cmd(f'nft {nft_add_element}') +    # Apply FRR filters +    zebra_daemon = 'zebra' +    # Save original configuration prior to starting any commit actions +    frr_cfg = frr.FRRConfig() + +    # The route-map used for the FIB (zebra) is part of the zebra daemon +    frr_cfg.load_configuration(zebra_daemon) +    frr_cfg.modify_section(f'^vrf .+', stop_pattern='^exit-vrf', remove_stop_mark=True) +    if 'frr_zebra_config' in vrf: +        frr_cfg.add_before(frr.default_add_before, vrf['frr_zebra_config']) +    frr_cfg.commit_configuration(zebra_daemon)      # return to default lookup preference when no VRF is configured      if 'name' not in vrf: diff --git a/src/conf_mode/vrf_vni.py b/src/conf_mode/vrf_vni.py deleted file mode 100755 index 585fdbebf..000000000 --- a/src/conf_mode/vrf_vni.py +++ /dev/null @@ -1,65 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright (C) 2020-2021 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/>. - -from sys import argv -from sys import exit - -from vyos.config import Config -from vyos.template import render_to_string -from vyos import ConfigError -from vyos import frr -from vyos import airbag -airbag.enable() - -frr_daemon = 'zebra' - -def get_config(config=None): -    if config: -        conf = config -    else: -        conf = Config() - -    base = ['vrf'] -    vrf = conf.get_config_dict(base, get_first_key=True) -    return vrf - -def verify(vrf): -    return None - -def generate(vrf): -    vrf['new_frr_config'] = render_to_string('frr/vrf-vni.frr.j2', vrf) -    return None - -def apply(vrf): -    # add configuration to FRR -    frr_cfg = frr.FRRConfig() -    frr_cfg.load_configuration(frr_daemon) -    frr_cfg.modify_section(f'^vrf .+', stop_pattern='^exit-vrf', remove_stop_mark=True) -    if 'new_frr_config' in vrf: -        frr_cfg.add_before(frr.default_add_before, vrf['new_frr_config']) -    frr_cfg.commit_configuration(frr_daemon) - -    return None - -if __name__ == '__main__': -    try: -        c = get_config() -        verify(c) -        generate(c) -        apply(c) -    except ConfigError as e: -        print(e) -        exit(1) diff --git a/src/etc/dhcp/dhclient-exit-hooks.d/vyatta-dhclient-hook b/src/etc/dhcp/dhclient-exit-hooks.d/03-vyatta-dhclient-hook index 49bb18372..49bb18372 100644 --- a/src/etc/dhcp/dhclient-exit-hooks.d/vyatta-dhclient-hook +++ b/src/etc/dhcp/dhclient-exit-hooks.d/03-vyatta-dhclient-hook diff --git a/src/etc/dhcp/dhclient-exit-hooks.d/99-run-user-hooks b/src/etc/dhcp/dhclient-exit-hooks.d/98-run-user-hooks index 442419d79..442419d79 100755 --- a/src/etc/dhcp/dhclient-exit-hooks.d/99-run-user-hooks +++ b/src/etc/dhcp/dhclient-exit-hooks.d/98-run-user-hooks diff --git a/src/etc/dhcp/dhclient-exit-hooks.d/ipsec-dhclient-hook b/src/etc/dhcp/dhclient-exit-hooks.d/99-ipsec-dhclient-hook index 1f1926e17..1f1926e17 100755 --- a/src/etc/dhcp/dhclient-exit-hooks.d/ipsec-dhclient-hook +++ b/src/etc/dhcp/dhclient-exit-hooks.d/99-ipsec-dhclient-hook diff --git a/src/etc/opennhrp/opennhrp-script.py b/src/etc/opennhrp/opennhrp-script.py index bf25a7331..688c7af2a 100755 --- a/src/etc/opennhrp/opennhrp-script.py +++ b/src/etc/opennhrp/opennhrp-script.py @@ -1,6 +1,6 @@  #!/usr/bin/env python3  # -# Copyright (C) 2021 VyOS maintainers and contributors +# Copyright (C) 2021-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 @@ -17,7 +17,7 @@  import os  import re  import sys -import vici +import vyos.ipsec  from json import loads  from pathlib import Path @@ -51,9 +51,8 @@ def vici_get_ipsec_uniqueid(conn: str, src_nbma: str,          logger.info(              f'Resolving IKE unique ids for: conn: {conn}, '              f'src_nbma: {src_nbma}, dst_nbma: {dst_nbma}') -        session: vici.Session = vici.Session()          list_ikeid: list[str] = [] -        list_sa = session.list_sas({'ike': conn}) +        list_sa: list = vyos.ipsec.get_vici_sas_by_name(conn, None)          for sa in list_sa:              if sa[conn]['local-host'].decode('ascii') == src_nbma \                      and sa[conn]['remote-host'].decode('ascii') == dst_nbma: @@ -78,16 +77,7 @@ def vici_ike_terminate(list_ikeid: list[str]) -> bool:          return False      try: -        session = vici.Session() -        for ikeid in list_ikeid: -            logger.info(f'Terminating IKE SA with id {ikeid}') -            session_generator = session.terminate( -                {'ike-id': ikeid, 'timeout': '-1'}) -            # a dummy `for` loop is required because of requirements -            # from vici. Without a full iteration on the output, the -            # command to vici may not be executed completely -            for _ in session_generator: -                pass +        vyos.ipsec.terminate_vici_ikeid_list(list_ikeid)          return True      except Exception as err:          logger.error(f'Failed to terminate SA for IKE ids {list_ikeid}: {err}') @@ -180,19 +170,7 @@ def vici_initiate(conn: str, child_sa: str, src_addr: str,          f'Trying to initiate connection. Name: {conn}, child sa: {child_sa}, '          f'src_addr: {src_addr}, dst_addr: {dest_addr}')      try: -        session = vici.Session() -        session_generator = session.initiate({ -            'ike': conn, -            'child': child_sa, -            'timeout': '-1', -            'my-host': src_addr, -            'other-host': dest_addr -        }) -        # a dummy `for` loop is required because of requirements -        # from vici. Without a full iteration on the output, the -        # command to vici may not be executed completely -        for _ in session_generator: -            pass +        vyos.ipsec.vici_initiate(conn, child_sa, src_addr, dest_addr)          return True      except Exception as err:          logger.error(f'Unable to initiate connection {err}') @@ -218,8 +196,11 @@ def vici_terminate(conn: str, src_addr: str, dest_addr: str) -> None:              f'No active sessions found for IKE profile {conn}, '              f'local NBMA {src_addr}, remote NBMA {dest_addr}')      else: -        vici_ike_terminate(ikeid_list) - +        try: +            vyos.ipsec.terminate_vici_ikeid_list(ikeid_list) +        except Exception as err: +            logger.error( +                f'Failed to terminate SA for IKE ids {ikeid_list}: {err}')  def iface_up(interface: str) -> None:      """Proceed tunnel interface UP event diff --git a/src/etc/systemd/system/hostapd@.service.d/override.conf b/src/etc/systemd/system/hostapd@.service.d/override.conf index bb8e81d7a..926c07f94 100644 --- a/src/etc/systemd/system/hostapd@.service.d/override.conf +++ b/src/etc/systemd/system/hostapd@.service.d/override.conf @@ -1,6 +1,8 @@  [Unit]  After=  After=vyos-router.service +ConditionFileNotEmpty= +ConditionFileNotEmpty=/run/hostapd/%i.conf  [Service]  WorkingDirectory=/run/hostapd diff --git a/src/helpers/vyos-failover.py b/src/helpers/vyos-failover.py index 0de945f20..03fb42f57 100755 --- a/src/helpers/vyos-failover.py +++ b/src/helpers/vyos-failover.py @@ -30,7 +30,7 @@ my_name = Path(__file__).stem  def is_route_exists(route, gateway, interface, metric):      """Check if route with expected gateway, dev and metric exists""" -    rc, data = rc_cmd(f'sudo ip --json route show protocol failover {route} ' +    rc, data = rc_cmd(f'ip --json route show protocol failover {route} '                        f'via {gateway} dev {interface} metric {metric}')      if rc == 0:          data = json.loads(data) @@ -72,6 +72,7 @@ def get_best_route_options(route, debug=False):                    f'best_metric: {best_metric}, best_iface: {best_interface}')          return best_gateway, best_interface, best_metric +  def is_port_open(ip, port):      """      Check connection to remote host and port @@ -91,32 +92,54 @@ def is_port_open(ip, port):      finally:          s.close() -def is_target_alive(target=None, iface='', proto='icmp', port=None, debug=False): -    """ -    Host availability check by ICMP, ARP, TCP -    Return True if target checks is successful -    % is_target_alive('192.0.2.1', 'eth1', proto='arp') -    True +def is_target_alive(target_list=None, iface='', proto='icmp', port=None, debug=False): +    """Check the availability of each target in the target_list using +    the specified protocol ICMP, ARP, TCP + +    Args: +        target_list (list): A list of IP addresses or hostnames to check. +        iface (str): The name of the network interface to use for the check. +        proto (str): The protocol to use for the check. Options are 'icmp', 'arp', or 'tcp'. +        port (int): The port number to use for the TCP check. Only applicable if proto is 'tcp'. +        debug (bool): If True, print debug information during the check. + +    Returns: +        bool: True if all targets are reachable, False otherwise. + +    Example: +        % is_target_alive(['192.0.2.1', '192.0.2.5'], 'eth1', proto='arp') +        True      """      if iface != '':          iface = f'-I {iface}' -    if proto == 'icmp': -        command = f'/usr/bin/ping -q {target} {iface} -n -c 2 -W 1' -        rc, response = rc_cmd(command) -        if debug: print(f'    [ CHECK-TARGET ]: [{command}] -- return-code [RC: {rc}]') -        if rc == 0: -            return True -    elif proto == 'arp': -        command = f'/usr/bin/arping -b -c 2 -f -w 1 -i 1 {iface} {target}' -        rc, response = rc_cmd(command) -        if debug: print(f'    [ CHECK-TARGET ]: [{command}] -- return-code [RC: {rc}]') -        if rc == 0: -            return True -    elif proto == 'tcp' and port is not None: -        return True if is_port_open(target, port) else False -    else: -        return False + +    for target in target_list: +        match proto: +            case 'icmp': +                command = f'/usr/bin/ping -q {target} {iface} -n -c 2 -W 1' +                rc, response = rc_cmd(command) +                if debug: +                    print(f'    [ CHECK-TARGET ]: [{command}] -- return-code [RC: {rc}]') +                if rc != 0: +                    return False + +            case 'arp': +                command = f'/usr/bin/arping -b -c 2 -f -w 1 -i 1 {iface} {target}' +                rc, response = rc_cmd(command) +                if debug: +                    print(f'    [ CHECK-TARGET ]: [{command}] -- return-code [RC: {rc}]') +                if rc != 0: +                    return False + +            case _ if proto == 'tcp' and port is not None: +                if not is_port_open(target, port): +                    return False + +            case _: +                return False + +    return True  if __name__ == '__main__': diff --git a/src/migration-scripts/bgp/3-to-4 b/src/migration-scripts/bgp/3-to-4 new file mode 100755 index 000000000..0df2fbec4 --- /dev/null +++ b/src/migration-scripts/bgp/3-to-4 @@ -0,0 +1,64 @@ +#!/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/>. + +# T5150: Rework CLI definitions to apply route-maps between routing daemons +#        and zebra/kernel + +from sys import argv +from sys import exit + +from vyos.configtree import ConfigTree + +if (len(argv) < 1): +    print("Must specify file name!") +    exit(1) + +file_name = argv[1] + +with open(file_name, 'r') as f: +    config_file = f.read() + +config = ConfigTree(config_file) + +bgp_base = ['protocols', 'bgp'] +# Check if BGP is configured - if so, migrate the CLI node +if config.exists(bgp_base): +    if config.exists(bgp_base + ['route-map']): +        tmp = config.return_value(bgp_base + ['route-map']) + +        config.set(['system', 'ip', 'protocol', 'bgp', 'route-map'], value=tmp) +        config.set_tag(['system', 'ip', 'protocol']) +        config.delete(bgp_base + ['route-map']) + + +# Check if vrf names are configured. Check if BGP is configured - if so, migrate +# the CLI node(s) +if config.exists(['vrf', 'name']): +    for vrf in config.list_nodes(['vrf', 'name']): +        vrf_base = ['vrf', 'name', vrf] +        if config.exists(vrf_base + ['protocols', 'bgp', 'route-map']): +            tmp = config.return_value(vrf_base + ['protocols', 'bgp', 'route-map']) + +            config.set(vrf_base + ['ip', 'protocol', 'bgp', 'route-map'], value=tmp) +            config.set_tag(vrf_base + ['ip', 'protocol', 'bgp']) +            config.delete(vrf_base + ['protocols', 'bgp', 'route-map']) + +try: +    with open(file_name, 'w') as f: +        f.write(config.to_string()) +except OSError as e: +    print(f'Failed to save the modified config: {e}') +    exit(1) diff --git a/src/migration-scripts/isis/2-to-3 b/src/migration-scripts/isis/2-to-3 new file mode 100755 index 000000000..4490feb0a --- /dev/null +++ b/src/migration-scripts/isis/2-to-3 @@ -0,0 +1,63 @@ +#!/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/>. + +# T5150: Rework CLI definitions to apply route-maps between routing daemons +#        and zebra/kernel + +from sys import argv +from sys import exit + +from vyos.configtree import ConfigTree + +if (len(argv) < 1): +    print("Must specify file name!") +    exit(1) + +file_name = argv[1] + +with open(file_name, 'r') as f: +    config_file = f.read() + +config = ConfigTree(config_file) + +isis_base = ['protocols', 'isis'] +# Check if IS-IS is configured - if so, migrate the CLI node +if config.exists(isis_base): +    if config.exists(isis_base + ['route-map']): +        tmp = config.return_value(isis_base + ['route-map']) + +        config.set(['system', 'ip', 'protocol', 'isis', 'route-map'], value=tmp) +        config.set_tag(['system', 'ip', 'protocol']) +        config.delete(isis_base + ['route-map']) + +# Check if vrf names are configured. Check if IS-IS is configured - if so, +# migrate  the CLI node(s) +if config.exists(['vrf', 'name']): +    for vrf in config.list_nodes(['vrf', 'name']): +        vrf_base = ['vrf', 'name', vrf] +        if config.exists(vrf_base + ['protocols', 'isis', 'route-map']): +            tmp = config.return_value(vrf_base + ['protocols', 'isis', 'route-map']) + +            config.set(vrf_base + ['ip', 'protocol', 'isis', 'route-map'], value=tmp) +            config.set_tag(vrf_base + ['ip', 'protocol', 'isis']) +            config.delete(vrf_base + ['protocols', 'isis', 'route-map']) + +try: +    with open(file_name, 'w') as f: +        f.write(config.to_string()) +except OSError as e: +    print(f'Failed to save the modified config: {e}') +    exit(1) diff --git a/src/migration-scripts/ospf/1-to-2 b/src/migration-scripts/ospf/1-to-2 new file mode 100755 index 000000000..a6beaf04e --- /dev/null +++ b/src/migration-scripts/ospf/1-to-2 @@ -0,0 +1,80 @@ +#!/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/>. + +# T5150: Rework CLI definitions to apply route-maps between routing daemons +#        and zebra/kernel + +from sys import argv +from sys import exit + +from vyos.configtree import ConfigTree + +if (len(argv) < 1): +    print("Must specify file name!") +    exit(1) + +file_name = argv[1] + +with open(file_name, 'r') as f: +    config_file = f.read() + +config = ConfigTree(config_file) + +ospf_base = ['protocols', 'ospf'] +# Check if OSPF is configured - if so, migrate the CLI node +if config.exists(ospf_base): +    if config.exists(ospf_base + ['route-map']): +        tmp = config.return_value(ospf_base + ['route-map']) + +        config.set(['system', 'ip', 'protocol', 'ospf', 'route-map'], value=tmp) +        config.set_tag(['system', 'ip', 'protocol']) +        config.delete(ospf_base + ['route-map']) + +ospfv3_base = ['protocols', 'ospfv3'] +# Check if OSPFv3 is configured - if so, migrate the CLI node +if config.exists(ospfv3_base): +    if config.exists(ospfv3_base + ['route-map']): +        tmp = config.return_value(ospfv3_base + ['route-map']) + +        config.set(['system', 'ipv6', 'protocol', 'ospfv3', 'route-map'], value=tmp) +        config.set_tag(['system', 'ipv6', 'protocol']) +        config.delete(ospfv3_base + ['route-map']) + +# Check if vrf names are configured. Check if OSPF/OSPFv3 is configured - if so, +# migrate the CLI node(s) +if config.exists(['vrf', 'name']): +    for vrf in config.list_nodes(['vrf', 'name']): +        vrf_base = ['vrf', 'name', vrf] +        if config.exists(vrf_base + ['protocols', 'ospf', 'route-map']): +            tmp = config.return_value(vrf_base + ['protocols', 'ospf', 'route-map']) + +            config.set(vrf_base + ['ip', 'protocol', 'ospf', 'route-map'], value=tmp) +            config.set_tag(vrf_base + ['ip', 'protocol', 'ospf']) +            config.delete(vrf_base + ['protocols', 'ospf', 'route-map']) + +        if config.exists(vrf_base + ['protocols', 'ospfv3', 'route-map']): +            tmp = config.return_value(vrf_base + ['protocols', 'ospfv3', 'route-map']) + +            config.set(vrf_base + ['ipv6', 'protocol', 'ospfv3', 'route-map'], value=tmp) +            config.set_tag(vrf_base + ['ipv6', 'protocol', 'ospfv6']) +            config.delete(vrf_base + ['protocols', 'ospfv3', 'route-map']) + +try: +    with open(file_name, 'w') as f: +        f.write(config.to_string()) +except OSError as e: +    print(f'Failed to save the modified config: {e}') +    exit(1) diff --git a/src/migration-scripts/quagga/10-to-11 b/src/migration-scripts/quagga/10-to-11 new file mode 100755 index 000000000..04fc16f79 --- /dev/null +++ b/src/migration-scripts/quagga/10-to-11 @@ -0,0 +1,51 @@ +#!/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/>. + +# T5150: Rework CLI definitions to apply route-maps between routing daemons +#        and zebra/kernel + +from sys import argv +from sys import exit + +from vyos.configtree import ConfigTree + +if (len(argv) < 1): +    print("Must specify file name!") +    exit(1) + +file_name = argv[1] + +with open(file_name, 'r') as f: +    config_file = f.read() + +config = ConfigTree(config_file) + +static_base = ['protocols', 'static'] +# Check if static routes are configured - if so, migrate the CLI node +if config.exists(static_base): +    if config.exists(static_base + ['route-map']): +        tmp = config.return_value(static_base + ['route-map']) + +        config.set(['system', 'ip', 'protocol', 'static', 'route-map'], value=tmp) +        config.set_tag(['system', 'ip', 'protocol']) +        config.delete(static_base + ['route-map']) + +try: +    with open(file_name, 'w') as f: +        f.write(config.to_string()) +except OSError as e: +    print(f'Failed to save the modified config: {e}') +    exit(1) diff --git a/src/migration-scripts/rip/0-to-1 b/src/migration-scripts/rip/0-to-1 new file mode 100755 index 000000000..60d510001 --- /dev/null +++ b/src/migration-scripts/rip/0-to-1 @@ -0,0 +1,51 @@ +#!/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/>. + +# T5150: Rework CLI definitions to apply route-maps between routing daemons +#        and zebra/kernel + +from sys import argv +from sys import exit + +from vyos.configtree import ConfigTree + +if (len(argv) < 1): +    print("Must specify file name!") +    exit(1) + +file_name = argv[1] + +with open(file_name, 'r') as f: +    config_file = f.read() + +config = ConfigTree(config_file) + +ripng_base = ['protocols', 'ripng'] +# Check if RIPng is configured - if so, migrate the CLI node +if config.exists(ripng_base): +    if config.exists(ripng_base + ['route-map']): +        tmp = config.return_value(ripng_base + ['route-map']) + +        config.set(['system', 'ipv6', 'protocol', 'ripng', 'route-map'], value=tmp) +        config.set_tag(['system', 'ipv6', 'protocol']) +        config.delete(ripng_base + ['route-map']) + +try: +    with open(file_name, 'w') as f: +        f.write(config.to_string()) +except OSError as e: +    print(f'Failed to save the modified config: {e}') +    exit(1) diff --git a/src/op_mode/dhcp.py b/src/op_mode/dhcp.py index 41da14065..fe7f252ba 100755 --- a/src/op_mode/dhcp.py +++ b/src/op_mode/dhcp.py @@ -264,8 +264,10 @@ def show_pool_statistics(raw: bool, family: ArgFamily, pool: typing.Optional[str  def show_server_leases(raw: bool, family: ArgFamily, pool: typing.Optional[str],                         sorted: typing.Optional[str], state: typing.Optional[ArgState]):      # if dhcp server is down, inactive leases may still be shown as active, so warn the user. -    if not is_systemd_service_running('isc-dhcp-server.service'): -        Warning('DHCP server is configured but not started. Data may be stale.') +    v = '6' if family == 'inet6' else '' +    service_name = 'DHCPv6' if family == 'inet6' else 'DHCP' +    if not is_systemd_service_running(f'isc-dhcp-server{v}.service'): +        Warning(f'{service_name} server is configured but not started. Data may be stale.')      v = 'v6' if family == 'inet6' else ''      if pool and pool not in _get_dhcp_pools(family=family): diff --git a/src/op_mode/dynamic_dns.py b/src/op_mode/dynamic_dns.py index 263a3b6a5..2cba33cc8 100755 --- a/src/op_mode/dynamic_dns.py +++ b/src/op_mode/dynamic_dns.py @@ -16,69 +16,63 @@  import os  import argparse -import jinja2  import sys  import time +from tabulate import tabulate  from vyos.config import Config  from vyos.util import call  cache_file = r'/run/ddclient/ddclient.cache' -OUT_TMPL_SRC = """ -{% for entry in hosts %} -ip address   : {{ entry.ip }} -host-name    : {{ entry.host }} -last update  : {{ entry.time }} -update-status: {{ entry.status }} +columns = { +    'host':        'Hostname', +    'ipv4':        'IPv4 address', +    'status-ipv4': 'IPv4 status', +    'ipv6':        'IPv6 address', +    'status-ipv6': 'IPv6 status', +    'mtime':       'Last update', +} + + +def _get_formatted_host_records(host_data): +    data_entries = [] +    for entry in host_data: +        data_entries.append([entry.get(key) for key in columns.keys()]) + +    header = columns.values() +    output = tabulate(data_entries, header, numalign='left') +    return output -{% endfor %} -"""  def show_status():      # A ddclient status file must not always exist      if not os.path.exists(cache_file):          sys.exit(0) -    data = { -        'hosts': [] -    } +    data = []      with open(cache_file, 'r') as f:          for line in f:              if line.startswith('#'):                  continue -            outp = { -                'host': '', -                'ip': '', -                'time': '' -            } - -            if 'host=' in line: -                host = line.split('host=')[1] -                if host: -                    outp['host'] = host.split(',')[0] - -            if 'ip=' in line: -                ip = line.split('ip=')[1] -                if ip: -                    outp['ip'] = ip.split(',')[0] - -            if 'mtime=' in line: -                mtime = line.split('mtime=')[1] -                if mtime: -                    outp['time'] = time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(int(mtime.split(',')[0], base=10))) +            props = {} +            # ddclient cache rows have properties in 'key=value' format separated by comma +            # we pick up the ones we are interested in +            for kvraw in line.split(' ')[0].split(','): +                k, v = kvraw.split('=') +                if k in columns.keys(): +                    props[k] = v -            if 'status=' in line: -                status = line.split('status=')[1] -                if status: -                    outp['status'] = status.split(',')[0] +            # Convert mtime to human readable format +            if 'mtime' in props: +                props['mtime'] = time.strftime( +                    "%Y-%m-%d %H:%M:%S", time.localtime(int(props['mtime'], base=10))) -            data['hosts'].append(outp) +            data.append(props) -    tmpl = jinja2.Template(OUT_TMPL_SRC) -    print(tmpl.render(data)) +    print(_get_formatted_host_records(data))  def update_ddns(): diff --git a/src/op_mode/ipsec.py b/src/op_mode/ipsec.py index 6acde08ea..7f4fb72e5 100755 --- a/src/op_mode/ipsec.py +++ b/src/op_mode/ipsec.py @@ -13,6 +13,7 @@  #  # 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 re  import sys  import typing @@ -487,6 +488,67 @@ def reset_ra(username: typing.Optional[str] = None):          vyos.ipsec.terminate_vici_ikeid_list(list_sa_id) +def reset_profile_dst(profile: str, tunnel: str, nbma_dst: str): +    if profile and tunnel and nbma_dst: +        ike_sa_name = f'dmvpn-{profile}-{tunnel}' +        try: +            # Get IKE SAs +            sa_list = convert_data( +                vyos.ipsec.get_vici_sas_by_name(ike_sa_name, None)) +            if not sa_list: +                raise vyos.opmode.IncorrectValue( +                    f'SA(s) for profile {profile} tunnel {tunnel} not found, aborting') +            sa_nbma_list = list([x for x in sa_list if +                                 ike_sa_name in x and x[ike_sa_name][ +                                     'remote-host'] == nbma_dst]) +            if not sa_nbma_list: +                raise vyos.opmode.IncorrectValue( +                    f'SA(s) for profile {profile} tunnel {tunnel} remote-host {nbma_dst} not found, aborting') +            # terminate IKE SAs +            vyos.ipsec.terminate_vici_ikeid_list(list( +                [x[ike_sa_name]['uniqueid'] for x in sa_nbma_list if +                 ike_sa_name in x])) +            # initiate IKE SAs +            for ike in sa_nbma_list: +                if ike_sa_name in ike: +                    vyos.ipsec.vici_initiate(ike_sa_name, 'dmvpn', +                                             ike[ike_sa_name]['local-host'], +                                             ike[ike_sa_name]['remote-host']) +            print( +                f'Profile {profile} tunnel {tunnel} remote-host {nbma_dst} reset result: success') +        except (vyos.ipsec.ViciInitiateError) as err: +            raise vyos.opmode.UnconfiguredSubsystem(err) +        except (vyos.ipsec.ViciCommandError) as err: +            raise vyos.opmode.IncorrectValue(err) + + +def reset_profile_all(profile: str, tunnel: str): +    if profile and tunnel: +        ike_sa_name = f'dmvpn-{profile}-{tunnel}' +        try: +            # Get IKE SAs +            sa_list: list = convert_data( +                vyos.ipsec.get_vici_sas_by_name(ike_sa_name, None)) +            if not sa_list: +                raise vyos.opmode.IncorrectValue( +                    f'SA(s) for profile {profile} tunnel {tunnel} not found, aborting') +            # terminate IKE SAs +            vyos.ipsec.terminate_vici_by_name(ike_sa_name, None) +            # initiate IKE SAs +            for ike in sa_list: +                if ike_sa_name in ike: +                    vyos.ipsec.vici_initiate(ike_sa_name, 'dmvpn', +                                             ike[ike_sa_name]['local-host'], +                                             ike[ike_sa_name]['remote-host']) +                print( +                    f'Profile {profile} tunnel {tunnel} remote-host {ike[ike_sa_name]["remote-host"]} reset result: success') +            print(f'Profile {profile} tunnel {tunnel} reset result: success') +        except (vyos.ipsec.ViciInitiateError) as err: +            raise vyos.opmode.UnconfiguredSubsystem(err) +        except (vyos.ipsec.ViciCommandError) as err: +            raise vyos.opmode.IncorrectValue(err) + +  def show_sa(raw: bool):      sa_data = _get_raw_data_sas()      if raw: diff --git a/src/op_mode/openvpn.py b/src/op_mode/openvpn.py index 37fdbcbeb..d9ae965c5 100755 --- a/src/op_mode/openvpn.py +++ b/src/op_mode/openvpn.py @@ -16,6 +16,7 @@  #  # +import json  import os  import sys  import typing @@ -25,6 +26,7 @@ import vyos.opmode  from vyos.util import bytes_to_human  from vyos.util import commit_in_progress  from vyos.util import call +from vyos.util import rc_cmd  from vyos.config import Config  ArgMode = typing.Literal['client', 'server', 'site_to_site'] @@ -63,7 +65,7 @@ def _get_interface_status(mode: str, interface: str) -> dict:      }      if not os.path.exists(status_file): -        raise vyos.opmode.DataUnavailable('No information for interface {interface}') +        return data      with open(status_file, 'r') as f:          lines = f.readlines() @@ -142,6 +144,25 @@ def _get_interface_status(mode: str, interface: str) -> dict:      return data + +def _get_interface_state(iface): +    rc, out = rc_cmd(f'ip --json link show dev {iface}') +    try: +        data = json.loads(out) +    except: +        return 'DOWN' +    return data[0].get('operstate', 'DOWN') + + +def _get_interface_description(iface): +    rc, out = rc_cmd(f'ip --json link show dev {iface}') +    try: +        data = json.loads(out) +    except: +        return '' +    return data[0].get('ifalias', '') + +  def _get_raw_data(mode: str) -> list:      data: list = []      conf = Config() @@ -154,6 +175,8 @@ def _get_raw_data(mode: str) -> list:                    conf_dict[x]['mode'].replace('-', '_') == mode]      for intf in interfaces:          d = _get_interface_status(mode, intf) +        d['state'] = _get_interface_state(intf) +        d['description'] = _get_interface_description(intf)          d['local_host'] = conf_dict[intf].get('local-host', '')          d['local_port'] = conf_dict[intf].get('local-port', '')          if conf.exists(f'interfaces openvpn {intf} server client'): diff --git a/src/op_mode/pki.py b/src/op_mode/pki.py index 1e78c3a03..b054690b0 100755 --- a/src/op_mode/pki.py +++ b/src/op_mode/pki.py @@ -87,6 +87,9 @@ def get_config_certificate(name=None):  def get_certificate_ca(cert, ca_certs):      # Find CA certificate for given certificate +    if not ca_certs: +        return None +      for ca_name, ca_dict in ca_certs.items():          if 'certificate' not in ca_dict:              continue diff --git a/src/op_mode/sflow.py b/src/op_mode/sflow.py new file mode 100755 index 000000000..88f70d6bd --- /dev/null +++ b/src/op_mode/sflow.py @@ -0,0 +1,108 @@ +#!/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 dbus +import sys + +from tabulate import tabulate + +from vyos.configquery import ConfigTreeQuery +from vyos.util import cmd + +import vyos.opmode + + +def _get_raw_sflow(): +    bus = dbus.SystemBus() +    config = ConfigTreeQuery() + +    interfaces = config.values('system sflow interface') +    servers = config.list_nodes('system sflow server') + +    sflow = bus.get_object('net.sflow.hsflowd', '/net/sflow/hsflowd') +    sflow_telemetry = dbus.Interface( +        sflow, dbus_interface='net.sflow.hsflowd.telemetry') +    agent_address = sflow_telemetry.GetAgent() +    samples_dropped = int(sflow_telemetry.Get('dropped_samples')) +    packet_drop_sent = int(sflow_telemetry.Get('event_samples')) +    samples_packet_sent = int(sflow_telemetry.Get('flow_samples')) +    samples_counter_sent = int(sflow_telemetry.Get('counter_samples')) +    datagrams_sent = int(sflow_telemetry.Get('datagrams')) +    rtmetric_samples = int(sflow_telemetry.Get('rtmetric_samples')) +    event_samples_suppressed = int(sflow_telemetry.Get('event_samples_suppressed')) +    samples_suppressed = int(sflow_telemetry.Get('flow_samples_suppressed')) +    counter_samples_suppressed = int( +        sflow_telemetry.Get("counter_samples_suppressed")) +    version = sflow_telemetry.GetVersion() + +    sflow_dict = { +        'agent_address': agent_address, +        'sflow_interfaces': interfaces, +        'sflow_servers': servers, +        'counter_samples_sent': samples_counter_sent, +        'datagrams_sent': datagrams_sent, +        'packet_drop_sent': packet_drop_sent, +        'packet_samples_dropped': samples_dropped, +        'packet_samples_sent': samples_packet_sent, +        'rtmetric_samples': rtmetric_samples, +        'event_samples_suppressed': event_samples_suppressed, +        'flow_samples_suppressed': samples_suppressed, +        'counter_samples_suppressed': counter_samples_suppressed, +        'hsflowd_version': version +    } +    return sflow_dict + + +def _get_formatted_sflow(data): +    table = [ +        ['Agent address', f'{data.get("agent_address")}'], +        ['sFlow interfaces', f'{data.get("sflow_interfaces", "n/a")}'], +        ['sFlow servers', f'{data.get("sflow_servers", "n/a")}'], +        ['Counter samples sent', f'{data.get("counter_samples_sent")}'], +        ['Datagrams sent', f'{data.get("datagrams_sent")}'], +        ['Packet samples sent', f'{data.get("packet_samples_sent")}'], +        ['Packet samples dropped', f'{data.get("packet_samples_dropped")}'], +        ['Packet drops sent', f'{data.get("packet_drop_sent")}'], +        ['Packet drops suppressed', f'{data.get("event_samples_suppressed")}'], +        ['Flow samples suppressed', f'{data.get("flow_samples_suppressed")}'], +        ['Counter samples suppressed', f'{data.get("counter_samples_suppressed")}'] +    ] + +    return tabulate(table) + + +def show(raw: bool): + +    config = ConfigTreeQuery() +    if not config.exists('system sflow'): +        raise vyos.opmode.UnconfiguredSubsystem( +            '"system sflow" is not configured!') + +    sflow_data = _get_raw_sflow() +    if raw: +        return sflow_data +    else: +        return _get_formatted_sflow(sflow_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/show_interfaces.py b/src/op_mode/show_interfaces.py deleted file mode 100755 index eac068274..000000000 --- a/src/op_mode/show_interfaces.py +++ /dev/null @@ -1,310 +0,0 @@ -#!/usr/bin/env python3 - -# Copyright 2017-2021 VyOS maintainers and contributors <maintainers@vyos.io> -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library 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 -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library.  If not, see <http://www.gnu.org/licenses/>. - -import os -import re -import sys -import glob -import argparse - -from vyos.ifconfig import Section -from vyos.ifconfig import Interface -from vyos.ifconfig import VRRP -from vyos.util import cmd, call - - -# interfaces = Sections.reserved() -interfaces = ['eno', 'ens', 'enp', 'enx', 'eth', 'vmnet', 'lo', 'tun', 'wan', 'pppoe'] -glob_ifnames = '/sys/class/net/({})*'.format('|'.join(interfaces)) - - -actions = {} -def register(name): -    """ -    Decorator to register a function into actions with a name. -    `actions[name]' can be used to call the registered functions. -    We wrap each function in a SIGPIPE handler as all registered functions -    can be subject to a broken pipe if there are a lot of interfaces. -    """ -    def _register(function): -        def handled_function(*args, **kwargs): -            try: -                function(*args, **kwargs) -            except BrokenPipeError: -                # Flush output to /dev/null and bail out. -                os.dup2(os.open(os.devnull, os.O_WRONLY), sys.stdout.fileno()) -                sys.exit(1) -        actions[name] = handled_function -        return handled_function -    return _register - - -def filtered_interfaces(ifnames, iftypes, vif, vrrp): -    """ -    get all the interfaces from the OS and returns them -    ifnames can be used to filter which interfaces should be considered - -    ifnames: a list of interfaces names to consider, empty do not filter -    return an instance of the interface class -    """ -    if isinstance(iftypes, list): -        for iftype in iftypes: -            yield from filtered_interfaces(ifnames, iftype, vif, vrrp) - -    for ifname in Section.interfaces(iftypes): -        # Bail out early if interface name not part of our search list -        if ifnames and ifname not in ifnames: -            continue - -        # As we are only "reading" from the interface - we must use the -        # generic base class which exposes all the data via a common API -        interface = Interface(ifname, create=False, debug=False) - -        # VLAN interfaces have a '.' in their name by convention -        if vif and not '.' in ifname: -            continue - -        if vrrp: -            vrrp_interfaces = VRRP.active_interfaces() -            if ifname not in vrrp_interfaces: -                continue - -        yield interface - - -def split_text(text, used=0): -    """ -    take a string and attempt to split it to fit with the width of the screen - -    text: the string to split -    used: number of characted already used in the screen -    """ -    no_tty = call('tty -s') - -    returned = cmd('stty size') if not no_tty else '' -    if len(returned) == 2: -        rows, columns = [int(_) for _ in returned] -    else: -        rows, columns = (40, 80) - -    desc_len = columns - used - -    line = '' -    for word in text.split(): -        if len(line) + len(word) < desc_len: -            line = f'{line} {word}' -            continue -        if line: -            yield line[1:] -        else: -            line = f'{line} {word}' - -    yield line[1:] - - -def get_counter_val(clear, now): -    """ -    attempt to correct a counter if it wrapped, copied from perl - -    clear: previous counter -    now:   the current counter -    """ -    # This function has to deal with both 32 and 64 bit counters -    if clear == 0: -        return now - -    # device is using 64 bit values assume they never wrap -    value = now - clear -    if (now >> 32) != 0: -        return value - -    # The counter has rolled.  If the counter has rolled -    # multiple times since the clear value, then this math -    # is meaningless. -    if (value < 0): -        value = (4294967296 - clear) + now - -    return value - - -@register('help') -def usage(*args): -    print(f"Usage: {sys.argv[0]} [intf=NAME|intf-type=TYPE|vif|vrrp] action=ACTION") -    print(f"  NAME = " + ' | '.join(Section.interfaces())) -    print(f"  TYPE = " + ' | '.join(Section.sections())) -    print(f"  ACTION = " + ' | '.join(actions)) -    sys.exit(1) - - -@register('allowed') -def run_allowed(**kwarg): -    sys.stdout.write(' '.join(Section.interfaces())) - - -def pppoe(ifname): -    out = cmd(f'ps -C pppd -f') -    if ifname in out: -        return 'C' -    elif ifname in [_.split('/')[-1] for _ in glob.glob('/etc/ppp/peers/pppoe*')]: -	    return 'D' -    return '' - - -@register('show') -def run_show_intf(ifnames, iftypes, vif, vrrp): -    handled = [] -    for interface in filtered_interfaces(ifnames, iftypes, vif, vrrp): -        handled.append(interface.ifname) -        cache = interface.operational.load_counters() - -        out = cmd(f'ip addr show {interface.ifname}') -        out = re.sub(f'^\d+:\s+','',out) -        if re.search('link/tunnel6', out): -            tunnel = cmd(f'ip -6 tun show {interface.ifname}') -            # tun0: ip/ipv6 remote ::2 local ::1 encaplimit 4 hoplimit 64 tclass inherit flowlabel inherit (flowinfo 0x00000000) -            tunnel = re.sub('.*encap', 'encap', tunnel) -            out = re.sub('(\n\s+)(link/tunnel6)', f'\g<1>{tunnel}\g<1>\g<2>', out) - -        print(out) - -        timestamp = int(cache.get('timestamp', 0)) -        if timestamp: -            when = interface.operational.strtime(timestamp) -            print(f'    Last clear: {when}') - -        description = interface.get_alias() -        if description: -            print(f'    Description: {description}') - -        print() -        print(interface.operational.formated_stats()) - -    for ifname in ifnames: -        if ifname not in handled and ifname.startswith('pppoe'): -            state = pppoe(ifname) -            if not state: -                continue -            string = { -                'C': 'Coming up', -                'D': 'Link down', -            }[state] -            print('{}: {}'.format(ifname, string)) - - -@register('show-brief') -def run_show_intf_brief(ifnames, iftypes, vif, vrrp): -    format1 = '%-16s %-33s %-4s %s' -    format2 = '%-16s %s' - -    print('Codes: S - State, L - Link, u - Up, D - Down, A - Admin Down') -    print(format1 % ("Interface", "IP Address", "S/L", "Description")) -    print(format1 % ("---------", "----------", "---", "-----------")) - -    handled = [] -    for interface in filtered_interfaces(ifnames, iftypes, vif, vrrp): -        handled.append(interface.ifname) - -        oper_state = interface.operational.get_state() -        admin_state = interface.get_admin_state() - -        intf = [interface.ifname,] - -        oper = ['u', ] if oper_state in ('up', 'unknown') else ['D', ] -        admin = ['u', ] if admin_state in ('up', 'unknown') else ['A', ] -        addrs = [_ for _ in interface.get_addr() if not _.startswith('fe80::')] or ['-', ] -        descs = list(split_text(interface.get_alias(),0)) - -        while intf or oper or admin or addrs or descs: -            i = intf.pop(0) if intf else '' -            a = addrs.pop(0) if addrs else '' -            d = descs.pop(0) if descs else '' -            s = [admin.pop(0)] if admin else [] -            l = [oper.pop(0)] if oper else [] -            if len(a) < 33: -                print(format1 % (i, a, '/'.join(s+l), d)) -            else: -                print(format2 % (i, a)) -                print(format1 % ('', '', '/'.join(s+l), d)) - -    for ifname in ifnames: -        if ifname not in handled and ifname.startswith('pppoe'): -            state = pppoe(ifname) -            if not state: -                continue -            string = { -                'C': 'u/D', -                'D': 'A/D', -            }[state] -            print(format1 % (ifname, '', string, '')) - - -@register('show-count') -def run_show_counters(ifnames, iftypes, vif, vrrp): -    formating = '%-12s %10s %10s     %10s %10s' -    print(formating % ('Interface', 'Rx Packets', 'Rx Bytes', 'Tx Packets', 'Tx Bytes')) - -    for interface in filtered_interfaces(ifnames, iftypes, vif, vrrp): -        oper = interface.operational.get_state() - -        if oper not in ('up','unknown'): -            continue - -        stats = interface.operational.get_stats() -        cache = interface.operational.load_counters() -        print(formating % ( -            interface.ifname, -            get_counter_val(cache['rx_packets'], stats['rx_packets']), -            get_counter_val(cache['rx_bytes'],   stats['rx_bytes']), -            get_counter_val(cache['tx_packets'], stats['tx_packets']), -            get_counter_val(cache['tx_bytes'],   stats['tx_bytes']), -        )) - - -@register('clear') -def run_clear_intf(ifnames, iftypes, vif, vrrp): -    for interface in filtered_interfaces(ifnames, iftypes, vif, vrrp): -        print(f'Clearing {interface.ifname}') -        interface.operational.clear_counters() - - -@register('reset') -def run_reset_intf(ifnames, iftypes, vif, vrrp): -    for interface in filtered_interfaces(ifnames, iftypes, vif, vrrp): -        interface.operational.reset_counters() - - -if __name__ == '__main__': -    parser = argparse.ArgumentParser(add_help=False, description='Show interface information') -    parser.add_argument('--intf', action="store", type=str, default='', help='only show the specified interface(s)') -    parser.add_argument('--intf-type', action="store", type=str, default='', help='only show the specified interface type') -    parser.add_argument('--action', action="store", type=str, default='show', help='action to perform') -    parser.add_argument('--vif', action='store_true', default=False, help="only show vif interfaces") -    parser.add_argument('--vrrp', action='store_true', default=False, help="only show vrrp interfaces") -    parser.add_argument('--help', action='store_true', default=False, help="show help") - -    args = parser.parse_args() - -    def missing(*args): -        print('Invalid action [{args.action}]') -        usage() - -    actions.get(args.action, missing)( -        [_ for _ in args.intf.split(' ') if _], -        [_ for _ in args.intf_type.split(' ') if _], -        args.vif, -        args.vrrp -    ) diff --git a/src/op_mode/show_techsupport_report.py b/src/op_mode/show_techsupport_report.py new file mode 100644 index 000000000..782004144 --- /dev/null +++ b/src/op_mode/show_techsupport_report.py @@ -0,0 +1,303 @@ +#!/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 os + +from typing import List +from vyos.util import rc_cmd +from vyos.ifconfig import Section +from vyos.ifconfig import Interface + + +def print_header(command: str) -> None: +    """Prints a command with headers '-'. + +    Example: + +    % print_header('Example command') + +    --------------- +    Example command +    --------------- +    """ +    header_length = len(command) * '-' +    print(f"\n{header_length}\n{command}\n{header_length}") + + +def execute_command(command: str, header_text: str) -> None: +    """Executes a command and prints the output with a header. + +    Example: +    % execute_command('uptime', "Uptime of the system") + +    -------------------- +    Uptime of the system +    -------------------- +    20:21:57 up  9:04,  5 users,  load average: 0.00, 0.00, 0.0 + +    """ +    print_header(header_text) +    try: +        rc, output = rc_cmd(command) +        print(output) +    except Exception as e: +        print(f"Error executing command: {command}") +        print(f"Error message: {e}") + + +def op(cmd: str) -> str: +    """Returns a command with the VyOS operational mode wrapper.""" +    return f'/opt/vyatta/bin/vyatta-op-cmd-wrapper {cmd}' + + +def get_ethernet_interfaces() -> List[Interface]: +    """Returns a list of Ethernet interfaces.""" +    return Section.interfaces('ethernet') + + +def show_version() -> None: +    """Prints the VyOS version and package changes.""" +    execute_command(op('show version'), 'VyOS Version and Package Changes') + + +def show_config_file() -> None: +    """Prints the contents of a configuration file with a header.""" +    execute_command('cat /opt/vyatta/etc/config/config.boot', 'Configuration file') + + +def show_running_config() -> None: +    """Prints the running configuration.""" +    execute_command(op('show configuration'), 'Running configuration') + + +def show_package_repository_config() -> None: +    """Prints the package repository configuration file.""" +    execute_command('cat /etc/apt/sources.list', 'Package Repository Configuration File') +    execute_command('ls -l /etc/apt/sources.list.d/', 'Repositories') + + +def show_user_startup_scripts() -> None: +    """Prints the user startup scripts.""" +    execute_command('cat /config/scripts/vyos-postconfig-bootup.script', 'User Startup Scripts') + + +def show_frr_config() -> None: +    """Prints the FRR configuration.""" +    execute_command('vtysh -c "show run"', 'FRR configuration') + + +def show_interfaces() -> None: +    """Prints the interfaces.""" +    execute_command(op('show interfaces'), 'Interfaces') + + +def show_interface_statistics() -> None: +    """Prints the interface statistics.""" +    execute_command('ip -s link show', 'Interface statistics') + + +def show_physical_interface_statistics() -> None: +    """Prints the physical interface statistics.""" +    execute_command('/usr/bin/true', 'Physical Interface statistics') +    for iface in get_ethernet_interfaces(): +        # Exclude vlans +        if '.' in iface: +            continue +        execute_command(f'ethtool --driver {iface}', f'ethtool --driver {iface}') +        execute_command(f'ethtool --statistics {iface}', f'ethtool --statistics {iface}') +        execute_command(f'ethtool --show-ring {iface}', f'ethtool --show-ring {iface}') +        execute_command(f'ethtool --show-coalesce {iface}', f'ethtool --show-coalesce {iface}') +        execute_command(f'ethtool --pause {iface}', f'ethtool --pause {iface}') +        execute_command(f'ethtool --show-features {iface}', f'ethtool --show-features {iface}') +        execute_command(f'ethtool --phy-statistics {iface}', f'ethtool --phy-statistics {iface}') +    execute_command('netstat --interfaces', 'netstat --interfaces') +    execute_command('netstat --listening', 'netstat --listening') +    execute_command('cat /proc/net/dev', 'cat /proc/net/dev') + + +def show_bridge() -> None: +    """Show bridge interfaces.""" +    execute_command(op('show bridge'), 'Show bridge') + + +def show_arp() -> None: +    """Prints ARP entries.""" +    execute_command(op('show arp'), 'ARP Table (Total entries)') +    execute_command(op('show ipv6 neighbors'), 'show ipv6 neighbors') + + +def show_route() -> None: +    """Prints routing information.""" + +    cmd_list_route = [ +        "show ip route bgp | head -108", +        "show ip route cache", +        "show ip route connected", +        "show ip route forward", +        "show ip route isis | head -108", +        "show ip route kernel", +        "show ip route ospf | head -108", +        "show ip route rip", +        "show ip route static", +        "show ip route summary", +        "show ip route supernets-only", +        "show ip route table all", +        "show ip route vrf all", +        "show ipv6 route bgp | head 108", +        "show ipv6 route cache", +        "show ipv6 route connected", +        "show ipv6 route forward", +        "show ipv6 route isis", +        "show ipv6 route kernel", +        "show ipv6 route ospf", +        "show ipv6 route rip", +        "show ipv6 route static", +        "show ipv6 route summary", +        "show ipv6 route table all", +        "show ipv6 route vrf all", +    ] +    for command in cmd_list_route: +        execute_command(op(command), command) + + +def show_firewall() -> None: +    """Prints firweall information.""" +    execute_command('sudo nft list ruleset', 'nft list ruleset') + + +def show_system() -> None: +    """Prints system parameters.""" +    execute_command(op('show system image version'), 'Show System Image Version') +    execute_command(op('show system image storage'), 'Show System Image Storage') + + +def show_date() -> None: +    """Print the current date.""" +    execute_command('date', 'Current Time') + + +def show_installed_packages() -> None: +    """Prints installed packages.""" +    execute_command('dpkg --list', 'Installed Packages') + + +def show_loaded_modules() -> None: +    """Prints loaded modules /proc/modules""" +    execute_command('cat /proc/modules', 'Loaded Modules') + + +def show_cpu_statistics() -> None: +    """Prints CPU statistics.""" +    execute_command('/usr/bin/true', 'CPU') +    execute_command('lscpu', 'Installed CPU\'s') +    execute_command('top --iterations 1 --batch-mode --accum-time-toggle', 'Cumulative CPU Time Used by Running Processes') +    execute_command('cat /proc/loadavg', 'Load Average') + + +def show_system_interrupts() -> None: +    """Prints system interrupts.""" +    execute_command('cat /proc/interrupts', 'Hardware Interrupt Counters') + + +def show_soft_irqs() -> None: +    """Prints soft IRQ's.""" +    execute_command('cat /proc/softirqs', 'Soft IRQ\'s') + + +def show_softnet_statistics() -> None: +    """Prints softnet statistics.""" +    execute_command('cat /proc/net/softnet_stat', 'cat /proc/net/softnet_stat') + + +def show_running_processes() -> None: +    """Prints current running processes""" +    execute_command('ps -ef', 'Running Processes') + + +def show_memory_usage() -> None: +    """Prints memory usage""" +    execute_command('/usr/bin/true', 'Memory') +    execute_command('cat /proc/meminfo', 'Installed Memory') +    execute_command('free', 'Memory Usage') + + +def list_disks(): +    disks = set() +    with open('/proc/partitions') as partitions_file: +        for line in partitions_file: +            fields = line.strip().split() +            if len(fields) == 4 and fields[3].isalpha() and fields[3] != 'name': +                disks.add(fields[3]) +    return disks + + +def show_storage() -> None: +    """Prints storage information.""" +    execute_command('cat /proc/devices', 'Devices') +    execute_command('cat /proc/partitions', 'Partitions') + +    for disk in list_disks(): +        execute_command(f'fdisk --list /dev/{disk}', f'Partitioning for disk {disk}') + + +def main(): +    # Configuration data +    show_version() +    show_config_file() +    show_running_config() +    show_package_repository_config() +    show_user_startup_scripts() +    show_frr_config() + +    # Interfaces +    show_interfaces() +    show_interface_statistics() +    show_physical_interface_statistics() +    show_bridge() +    show_arp() + +    # Routing +    show_route() + +    # Firewall +    show_firewall() + +    # System +    show_system() +    show_date() +    show_installed_packages() +    show_loaded_modules() + +    # CPU +    show_cpu_statistics() +    show_system_interrupts() +    show_soft_irqs() +    show_softnet_statistics() + +    # Memory +    show_memory_usage() + +    # Storage +    show_storage() + +    # Processes +    show_running_processes() + +    # TODO: Get information from clouds + + +if __name__ == "__main__": +    main() diff --git a/src/op_mode/vpn_ipsec.py b/src/op_mode/vpn_ipsec.py index 2392cfe92..b81d1693e 100755 --- a/src/op_mode/vpn_ipsec.py +++ b/src/op_mode/vpn_ipsec.py @@ -16,12 +16,12 @@  import re  import argparse -from subprocess import TimeoutExpired  from vyos.util import call  SWANCTL_CONF = '/etc/swanctl/swanctl.conf' +  def get_peer_connections(peer, tunnel, return_all = False):      search = rf'^[\s]*(peer_{peer}_(tunnel_[\d]+|vti)).*'      matches = [] @@ -34,57 +34,6 @@ def get_peer_connections(peer, tunnel, return_all = False):                      matches.append(result[1])      return matches -def reset_peer(peer, tunnel): -    if not peer: -        print('Invalid peer, aborting') -        return - -    conns = get_peer_connections(peer, tunnel, return_all = (not tunnel or tunnel == 'all')) - -    if not conns: -        print('Tunnel(s) not found, aborting') -        return - -    result = True -    for conn in conns: -        try: -            call(f'/usr/sbin/ipsec down {conn}{{*}}', timeout = 10) -            call(f'/usr/sbin/ipsec up {conn}', timeout = 10) -        except TimeoutExpired as e: -            print(f'Timed out while resetting {conn}') -            result = False - - -    print('Peer reset result: ' + ('success' if result else 'failed')) - -def get_profile_connection(profile, tunnel = None): -    search = rf'(dmvpn-{profile}-[\w]+)' if tunnel == 'all' else rf'(dmvpn-{profile}-{tunnel})' -    with open(SWANCTL_CONF, 'r') as f: -        for line in f.readlines(): -            result = re.search(search, line) -            if result: -                return result[1] -    return None - -def reset_profile(profile, tunnel): -    if not profile: -        print('Invalid profile, aborting') -        return - -    if not tunnel: -        print('Invalid tunnel, aborting') -        return - -    conn = get_profile_connection(profile) - -    if not conn: -        print('Profile not found, aborting') -        return - -    call(f'/usr/sbin/ipsec down {conn}') -    result = call(f'/usr/sbin/ipsec up {conn}') - -    print('Profile reset result: ' + ('success' if result == 0 else 'failed'))  def debug_peer(peer, tunnel):      peer = peer.replace(':', '-') @@ -119,6 +68,7 @@ def debug_peer(peer, tunnel):      for conn in conns:          call(f'/usr/sbin/ipsec statusall | grep {conn}') +  if __name__ == '__main__':      parser = argparse.ArgumentParser()      parser.add_argument('--action', help='Control action', required=True) @@ -127,9 +77,6 @@ if __name__ == '__main__':      args = parser.parse_args() -    if args.action == 'reset-peer': -        reset_peer(args.name, args.tunnel) -    elif args.action == "reset-profile": -        reset_profile(args.name, args.tunnel) -    elif args.action == "vpn-debug": + +    if args.action == "vpn-debug":          debug_peer(args.name, args.tunnel) | 
