diff options
205 files changed, 2466 insertions, 1761 deletions
@@ -61,12 +61,7 @@ op_mode_definitions: $(op_xml_obj) # XXX: test if there are empty node.def files - this is not allowed as these # could mask help strings or mandatory priority statements - #find $(OP_TMPL_DIR) -name node.def -type f -empty -exec false {} + || sh -c 'echo "There are empty node.def files! Check your interface definitions." && exit 1' - -.PHONY: component_versions -.ONESHELL: -component_versions: interface_definitions - $(CURDIR)/scripts/build-component-versions $(BUILD_DIR)/interface-definitions $(DATA_DIR) + find $(OP_TMPL_DIR) -name node.def -type f -empty -exec false {} + || sh -c 'echo "There are empty node.def files! Check your interface definitions." && exit 1' .PHONY: vyshim vyshim: @@ -77,7 +72,7 @@ vyxdp: $(MAKE) -C $(XDP_DIR) .PHONY: all -all: clean interface_definitions op_mode_definitions component_versions vyshim +all: clean interface_definitions op_mode_definitions vyshim .PHONY: clean clean: @@ -89,7 +84,7 @@ clean: .PHONY: test test: - set -e; python3 -m compileall -q -x '/vmware-tools/scripts/' . + set -e; python3 -m compileall -q -x '/vmware-tools/scripts/, /ppp/' . PYTHONPATH=python/ python3 -m "nose" --with-xunit src --with-coverage --cover-erase --cover-xml --cover-package src/conf_mode,src/op_mode,src/completion,src/helpers,src/validators,src/tests --verbose .PHONY: sonar diff --git a/data/configd-include.json b/data/configd-include.json index 3b4e2925b..6893aaa86 100644 --- a/data/configd-include.json +++ b/data/configd-include.json @@ -6,7 +6,6 @@ "dhcpv6_relay.py", "dns_forwarding.py", "dynamic_dns.py", -"firewall_options.py", "host_name.py", "https.py", "igmp_proxy.py", @@ -69,5 +68,6 @@ "vpn_pptp.py", "vpn_sstp.py", "vrf.py", +"vrf_vni.py", "vrrp.py" ] diff --git a/data/templates/accel-ppp/l2tp.config.tmpl b/data/templates/accel-ppp/l2tp.config.tmpl index 070a966b7..44c96b935 100644 --- a/data/templates/accel-ppp/l2tp.config.tmpl +++ b/data/templates/accel-ppp/l2tp.config.tmpl @@ -150,3 +150,4 @@ vendor={{ radius_shaper_vendor }} [cli] tcp=127.0.0.1:2004 sessions-columns=ifname,username,calling-sid,ip,{{ ip6_column | join(',') }}{{ ',' if ip6_column }}rate-limit,type,comp,state,rx-bytes,tx-bytes,uptime + diff --git a/data/templates/frr/bgpd.frr.tmpl b/data/templates/frr/bgpd.frr.tmpl index aa297876b..96815836b 100644 --- a/data/templates/frr/bgpd.frr.tmpl +++ b/data/templates/frr/bgpd.frr.tmpl @@ -257,6 +257,9 @@ router bgp {{ local_as }} {{ 'vrf ' ~ vrf if vrf is defined and vrf is not none address-family ipv6 flowspec {% elif afi == 'l2vpn_evpn' %} address-family l2vpn evpn +{% if afi_config.rd is defined and afi_config.rd is not none %} + rd {{ afi_config.rd }} +{% endif %} {% endif %} {% if afi_config.aggregate_address is defined and afi_config.aggregate_address is not none %} {% for ip in afi_config.aggregate_address %} @@ -294,23 +297,39 @@ router bgp {{ local_as }} {{ 'vrf ' ~ vrf if vrf is defined and vrf is not none {% if afi_config.advertise is defined and afi_config.advertise is not none %} {% for adv_afi, adv_afi_config in afi_config.advertise.items() %} {% if adv_afi_config.unicast is defined and adv_afi_config.unicast is not none %} - advertise {{ adv_afi }} unicast {{ 'route-map ' ~ adv_afi_config.unicast.route_map if adv_afi_config.unicast.route_map is defined }} + advertise {{ adv_afi }} unicast {{ 'route-map ' ~ adv_afi_config.unicast.route_map if adv_afi_config.unicast.route_map is defined }} {% endif %} {% endfor %} {% endif %} {% if afi_config.distance is defined and afi_config.distance is not none %} {% if afi_config.distance is defined and afi_config.distance.external is defined and afi_config.distance.internal is defined and afi_config.distance.local is defined %} - distance bgp {{ afi_config.distance.external }} {{ afi_config.distance.internal }} {{ afi_config.distance.local }} + distance bgp {{ afi_config.distance.external }} {{ afi_config.distance.internal }} {{ afi_config.distance.local }} {% endif %} {% if afi_config.distance.prefix is defined and afi_config.distance.prefix is not none %} {% for prefix in afi_config.distance.prefix %} - distance {{ afi_config.distance.prefix[prefix].distance }} {{ prefix }} + distance {{ afi_config.distance.prefix[prefix].distance }} {{ prefix }} +{% endfor %} +{% endif %} +{% endif %} +{% if afi_config.export is defined and afi_config.export.vpn is defined %} + export vpn +{% endif %} +{% if afi_config.import is defined and afi_config.import is not none %} +{% if afi_config.import.vpn is defined %} + import vpn +{% endif %} +{% if afi_config.import.vrf is defined and afi_config.import.vrf is not none %} +{% for vrf in afi_config.import.vrf %} + import vrf {{ vrf }} {% endfor %} {% endif %} {% endif %} +{% if afi_config.label is defined and afi_config.label.vpn is defined and afi_config.label.vpn.export is defined and afi_config.label.vpn.export is not none %} + label vpn export {{ afi_config.label.vpn.export }} +{% endif %} {% if afi_config.local_install is defined and afi_config.local_install is not none %} {% for interface in afi_config.local_install.interface %} - local-install {{ interface }} + local-install {{ interface }} {% endfor %} {% endif %} {% if afi_config.advertise_all_vni is defined %} @@ -326,26 +345,47 @@ router bgp {{ local_as }} {{ 'vrf ' ~ vrf if vrf is defined and vrf is not none advertise-svi-ip {% endif %} {% if afi_config.rt_auto_derive is defined %} - autort rfc8365-compatible + autort rfc8365-compatible {% endif %} {% if afi_config.flooding is defined and afi_config.flooding.disable is defined %} - flooding disable + flooding disable {% endif %} {% if afi_config.flooding is defined and afi_config.flooding.head_end_replication is defined %} - flooding head-end-replication + flooding head-end-replication {% endif %} -{% if afi_config.rd is defined and afi_config.rd is not none %} - rd {{ afi_config.rd }} +{% if afi_config.rd is defined and afi_config.rd.vpn is defined and afi_config.rd.vpn.export is defined %} + rd vpn export {{ afi_config.rd.vpn.export }} {% endif %} {% if afi_config.route_target is defined and afi_config.route_target is not none %} +{% if afi_config.route_target.vpn is defined and afi_config.route_target.vpn is not none %} +{% if afi_config.route_target.vpn.both is defined and afi_config.route_target.vpn.both is not none %} + route-target vpn both {{ afi_config.route_target.vpn.both }} +{% else %} +{% if afi_config.route_target.vpn.export is defined and afi_config.route_target.vpn.export is not none %} + route-target vpn export {{ afi_config.route_target.vpn.export }} +{% endif %} +{% if afi_config.route_target.vpn.import is defined and afi_config.route_target.vpn.import is not none %} + route-target vpn import {{ afi_config.route_target.vpn.import }} +{% endif %} +{% endif %} +{% endif %} {% if afi_config.route_target.both is defined and afi_config.route_target.both is not none %} - route-target both {{ afi_config.route_target.both }} + route-target both {{ afi_config.route_target.both }} +{% else %} +{% if afi_config.route_target.export is defined and afi_config.route_target.export is not none %} + route-target export {{ afi_config.route_target.export }} +{% endif %} +{% if afi_config.route_target.import is defined and afi_config.route_target.import is not none %} + route-target import {{ afi_config.route_target.import }} +{% endif %} {% endif %} -{% if afi_config.route_target.export is defined and afi_config.route_target.export is not none %} - route-target export {{ afi_config.route_target.export }} +{% endif %} +{% if afi_config.route_map is defined and afi_config.route_map.vpn is defined and afi_config.route_map.vpn is not none %} +{% if afi_config.route_map.vpn.export is defined and afi_config.route_map.vpn.export is not none %} + route-map vpn export {{ afi_config.route_map.vpn.export }} {% endif %} -{% if afi_config.route_target.import is defined and afi_config.route_target.import is not none %} - route-target import {{ afi_config.route_target.import }} +{% if afi_config.route_map.vpn.import is defined and afi_config.route_map.vpn.import is not none %} + route-map vpn import {{ afi_config.route_map.vpn.import }} {% endif %} {% endif %} {% if afi_config.vni is defined and afi_config.vni is not none %} diff --git a/data/templates/frr/ospfv3.frr.tmpl b/data/templates/frr/ospf6d.frr.tmpl index 0026c0d2c..0026c0d2c 100644 --- a/data/templates/frr/ospfv3.frr.tmpl +++ b/data/templates/frr/ospf6d.frr.tmpl diff --git a/data/templates/frr/ospf.frr.tmpl b/data/templates/frr/ospfd.frr.tmpl index 36aa699a9..be39519c3 100644 --- a/data/templates/frr/ospf.frr.tmpl +++ b/data/templates/frr/ospfd.frr.tmpl @@ -14,6 +14,12 @@ interface {{ iface }} {{ 'vrf ' + vrf if vrf is defined and vrf is not none }} {% endif %} {% endif %} {% endif %} +{% if iface_config.area is defined and iface_config.area is not none %} + ip ospf area {{ iface_config.area }} +{% endif %} +{% if iface_config.bandwidth is defined and iface_config.bandwidth is not none %} + bandwidth {{ iface_config.bandwidth }} +{% endif %} {% if iface_config.cost is defined and iface_config.cost is not none %} ip ospf cost {{ iface_config.cost }} {% endif %} @@ -43,9 +49,6 @@ interface {{ iface }} {{ 'vrf ' + vrf if vrf is defined and vrf is not none }} {% if iface_config.network is defined and iface_config.network is not none %} ip ospf network {{ iface_config.network }} {% endif %} -{% if iface_config.bandwidth is defined and iface_config.bandwidth is not none %} - bandwidth {{ iface_config.bandwidth }} -{% endif %} ! {% endfor %} {% endif %} @@ -155,15 +158,19 @@ router ospf {{ 'vrf ' + vrf if vrf is defined and vrf is not none }} ospf router-id {{ parameters.router_id }} {% endif %} {% endif %} -{% for interface in passive_interface if passive_interface is defined %} +{% if passive_interface is defined and passive_interface is not none %} +{% for interface in passive_interface %} passive-interface {{ interface }} -{% endfor %} -{% for interface in passive_interface_exclude if passive_interface_exclude is defined %} -{% if interface.startswith('vlink') %} +{% endfor %} +{% endif %} +{% if passive_interface_exclude is defined and passive_interface_exclude is not none %} +{% for interface in passive_interface_exclude if passive_interface_exclude is defined %} +{% if interface.startswith('vlink') %} {% set interface = interface.upper() %} -{% endif %} +{% endif %} no passive-interface {{ interface }} -{% endfor %} +{% endfor %} +{% endif %} {% if redistribute is defined and redistribute is not none %} {% for protocol, options in redistribute.items() %} redistribute {{ protocol }} {{ 'metric ' + options.metric if options.metric is defined }} {{ 'metric-type ' + options.metric_type if options.metric_type is defined }} {{ 'route-map ' + options.route_map if options.route_map is defined }} diff --git a/data/templates/frr/policy.frr.tmpl b/data/templates/frr/policy.frr.tmpl index 89bd558dc..51adc1902 100644 --- a/data/templates/frr/policy.frr.tmpl +++ b/data/templates/frr/policy.frr.tmpl @@ -283,6 +283,9 @@ route-map {{ route_map }} {{ rule_config.action }} {{ rule }} {% if rule_config.set.large_community is defined and rule_config.set.large_community is not none %} set large-community {{ rule_config.set.large_community }} {% endif %} +{% if rule_config.set.large_comm_list_delete is defined and rule_config.set.large_comm_list_delete is not none %} + set large-comm-list {{ rule_config.set.large_comm_list_delete }} delete +{% endif %} {% if rule_config.set.local_preference is defined and rule_config.set.local_preference is not none %} set local-preference {{ rule_config.set.local_preference }} {% endif %} diff --git a/data/templates/frr/static_routes_macro.j2 b/data/templates/frr/static_routes_macro.j2 index f10b58047..3b432b49b 100644 --- a/data/templates/frr/static_routes_macro.j2 +++ b/data/templates/frr/static_routes_macro.j2 @@ -5,7 +5,7 @@ {% if prefix_config.dhcp_interface is defined and prefix_config.dhcp_interface is not none %} {% set next_hop = prefix_config.dhcp_interface | get_dhcp_router %} {% if next_hop is defined and next_hop is not none %} -{{ ip_ipv6 }} route {{ prefix }} {{ next_hop }} +{{ ip_ipv6 }} route {{ prefix }} {{ next_hop }} {{ prefix_config.dhcp_interface }} {% endif %} {% endif %} {% if prefix_config.interface is defined and prefix_config.interface is not none %} diff --git a/data/templates/frr/vrf-vni.frr.tmpl b/data/templates/frr/vrf-vni.frr.tmpl new file mode 100644 index 000000000..51d4ede1b --- /dev/null +++ b/data/templates/frr/vrf-vni.frr.tmpl @@ -0,0 +1,7 @@ +{% if vrf is defined and vrf is not none %} +vrf {{ vrf }} +{% if vni is defined and vni is not none %} + vni {{ vni }} +{% endif %} + exit-vrf +{% endif %} diff --git a/data/templates/frr/vrf.frr.tmpl b/data/templates/frr/vrf.frr.tmpl deleted file mode 100644 index 299c9719e..000000000 --- a/data/templates/frr/vrf.frr.tmpl +++ /dev/null @@ -1,9 +0,0 @@ -{% if name is defined and name is not none %} -{% for vrf, vrf_config in name.items() %} -vrf {{ vrf }} -{% if vrf_config.vni is defined and vrf_config.vni is not none %} - vni {{ vrf_config.vni }} -{% endif %} - exit-vrf -{% endfor %} -{% endif %} diff --git a/data/templates/https/nginx.default.tmpl b/data/templates/https/nginx.default.tmpl index b40ddcc74..2f8aa06c2 100644 --- a/data/templates/https/nginx.default.tmpl +++ b/data/templates/https/nginx.default.tmpl @@ -17,7 +17,7 @@ server { listen {{ server.port }} ssl; listen [::]:{{ server.port }} ssl; {% else %} - listen {{ server.address }}:{{ server.port }} ssl; + listen {{ server.address | bracketize_ipv6 }}:{{ server.port }} ssl; {% endif %} {% for name in server.name %} diff --git a/data/templates/ipsec/swanctl/peer.tmpl b/data/templates/ipsec/swanctl/peer.tmpl index dd29ea7d4..019f9e0d7 100644 --- a/data/templates/ipsec/swanctl/peer.tmpl +++ b/data/templates/ipsec/swanctl/peer.tmpl @@ -17,10 +17,10 @@ {% if ike.key_exchange is defined and ike.key_exchange == "ikev1" and ike.mode is defined and ike.mode == "aggressive" %} aggressive = yes {% endif %} + rekey_time = {{ ike.lifetime }}s mobike = {{ "yes" if ike.mobike is not defined or ike.mobike == "enable" else "no" }} {% if peer[0:1] == '@' %} keyingtries = 0 - rekey_time = 0 reauth_time = 0 {% elif peer_conf.connection_type is not defined or peer_conf.connection_type == 'initiate' %} keyingtries = 0 @@ -57,6 +57,7 @@ {% set vti_esp = esp_group[ peer_conf.vti.esp_group ] if peer_conf.vti.esp_group is defined else esp_group[ peer_conf.default_esp_group ] %} peer_{{ name }}_vti { esp_proposals = {{ vti_esp | get_esp_ike_cipher | join(',') }} + life_time = {{ vti_esp.lifetime }}s local_ts = 0.0.0.0/0,::/0 remote_ts = 0.0.0.0/0,::/0 updown = "/etc/ipsec.d/vti-up-down {{ peer_conf.vti.bind }} {{ peer_conf.dhcp_interface if peer_conf.dhcp_interface is defined else 'no' }}" @@ -87,6 +88,7 @@ {% set remote_suffix = '[{0}/{1}]'.format(proto, remote_port) if proto or remote_port else '' %} peer_{{ name }}_tunnel_{{ tunnel_id }} { esp_proposals = {{ tunnel_esp | get_esp_ike_cipher | join(',') }} + life_time = {{ tunnel_esp.lifetime }}s {% if tunnel_esp.mode is not defined or tunnel_esp.mode == 'tunnel' %} {% if tunnel_conf.local is defined and tunnel_conf.local.prefix is defined %} {% set local_prefix = tunnel_conf.local.prefix if 'any' not in tunnel_conf.local.prefix else ['0.0.0.0/0', '::/0'] %} diff --git a/data/templates/ipsec/swanctl/profile.tmpl b/data/templates/ipsec/swanctl/profile.tmpl index 0a7268405..66bcaa776 100644 --- a/data/templates/ipsec/swanctl/profile.tmpl +++ b/data/templates/ipsec/swanctl/profile.tmpl @@ -7,7 +7,7 @@ dmvpn-{{ name }}-{{ interface }} { proposals = {{ ike_group[profile_conf.ike_group] | get_esp_ike_cipher | join(',') }} version = {{ ike.key_exchange[4:] if ike is defined and ike.key_exchange is defined else "0" }} - rekey_time = {{ ike.lifetime }}s + life_time = {{ ike.lifetime }}s keyingtries = 0 {% if profile_conf.authentication is defined and profile_conf.authentication.mode is defined and profile_conf.authentication.mode == 'pre-shared-secret' %} local { diff --git a/data/templates/ipsec/swanctl/remote_access.tmpl b/data/templates/ipsec/swanctl/remote_access.tmpl index 456842488..f906836c6 100644 --- a/data/templates/ipsec/swanctl/remote_access.tmpl +++ b/data/templates/ipsec/swanctl/remote_access.tmpl @@ -10,7 +10,9 @@ send_certreq = no rekey_time = {{ ike.lifetime }}s keyingtries = 0 +{% if rw_conf.unique is defined and rw_conf.unique is not none %} unique = {{ rw_conf.unique }} +{% endif %} {% if rw_conf.pool is defined and rw_conf.pool is not none %} pools = {{ rw_conf.pool | join(',') }} {% endif %} diff --git a/data/templates/proxy-ndp/ndppd.conf.tmpl b/data/templates/ndppd/ndppd.conf.tmpl index ccd1d37ad..502dab5b8 100644 --- a/data/templates/proxy-ndp/ndppd.conf.tmpl +++ b/data/templates/ndppd/ndppd.conf.tmpl @@ -6,10 +6,10 @@ # interface. # # For some services, such as nat66, because it runs -# stateless, it needs to rely on NDP Proxy to respond +# stateless, it needs to rely on NDP Proxy to respond # to NDP requests. # -# When using nat66 source rules, NDP Proxy needs +# When using nat66 source rules, NDP Proxy needs # to be enabled # ######################################################## @@ -21,7 +21,7 @@ {% if config.outbound_interface not in global.ndppd_interfaces %} {% set global.ndppd_interfaces = global.ndppd_interfaces + [config.outbound_interface] %} {% endif %} -{% if config.translation.address is defined and config.translation.address | is_ip_network %} +{% if config.translation is defined and config.translation.address is defined and config.translation.address | is_ip_network %} {% set global.ndppd_prefixs = global.ndppd_prefixs + [{'interface':config.outbound_interface,'rule':config.translation.address}] %} {% endif %} {% endif %} @@ -41,4 +41,4 @@ proxy {{ interface }} { {% endif %} {% endfor %} } -{% endfor %} +{% endfor %} diff --git a/data/templates/openvpn/server.conf.tmpl b/data/templates/openvpn/server.conf.tmpl index d9f01310e..9b07a9ba2 100644 --- a/data/templates/openvpn/server.conf.tmpl +++ b/data/templates/openvpn/server.conf.tmpl @@ -74,6 +74,16 @@ topology {{ server.topology }} {% for subnet in server.subnet %} {% if subnet | is_ipv4 %} server {{ subnet | address_from_cidr }} {{ subnet | netmask_from_cidr }} nopool +{# First ip address is used as gateway. It's allows to use metrics #} +{% if server.push_route is defined and server.push_route is not none %} +{% for route, route_config in server.push_route.items() %} +{% if route | is_ipv4 %} +push "route {{ route | address_from_cidr }} {{ route | netmask_from_cidr }} {{ subnet | first_host_address }} {{ route_config.metric if route_config.metric is defined else "0" }}" +{% elif route | is_ipv6 %} +push "route-ipv6 {{ route }}" +{% endif %} +{% endfor %} +{% endif %} {# OpenVPN assigns the first IP address to its local interface so the pool used #} {# in net30 topology - where each client receives a /30 must start from the second subnet #} {% if server.topology is defined and server.topology == 'net30' %} @@ -106,15 +116,6 @@ management /run/openvpn/openvpn-mgmt-intf unix ccd-exclusive {% endif %} -{% if server.push_route is defined and server.push_route is not none %} -{% for route in server.push_route %} -{% if route | is_ipv4 %} -push "route {{ route | address_from_cidr }} {{ route | netmask_from_cidr }}" -{% elif route | is_ipv6 %} -push "route-ipv6 {{ route }}" -{% endif %} -{% endfor %} -{% endif %} {% if server.name_server is defined and server.name_server is not none %} {% for nameserver in server.name_server %} {% if nameserver | is_ipv4 %} diff --git a/data/templates/pppoe/ipv6-up.script.tmpl b/data/templates/pppoe/ipv6-up.script.tmpl index 7e1bc33b4..da73cb4d5 100644 --- a/data/templates/pppoe/ipv6-up.script.tmpl +++ b/data/templates/pppoe/ipv6-up.script.tmpl @@ -7,43 +7,6 @@ if [ "$6" != "{{ ifname }}" ]; then exit fi -{% if ipv6 is defined and ipv6.address is defined and ipv6.address.autoconf is defined %} -# add some info to syslog -DIALER_PID=$(cat /var/run/{{ ifname }}.pid) -logger -t pppd[$DIALER_PID] "executing $0" -logger -t pppd[$DIALER_PID] "configuring interface {{ ifname }} via {{ source_interface }}" - -# Configure interface-specific Host/Router behaviour. -# Note: It is recommended to have the same setting on all interfaces; mixed -# router/host scenarios are rather uncommon. Possible values are: -# -# 0 Forwarding disabled -# 1 Forwarding enabled -# -echo 1 > /proc/sys/net/ipv6/conf/{{ ifname }}/forwarding - -# Accept Router Advertisements; autoconfigure using them. -# -# It also determines whether or not to transmit Router -# Solicitations. If and only if the functional setting is to -# accept Router Advertisements, Router Solicitations will be -# transmitted. Possible values are: -# -# 0 Do not accept Router Advertisements. -# 1 Accept Router Advertisements if forwarding is disabled. -# 2 Overrule forwarding behaviour. Accept Router Advertisements -# even if forwarding is enabled. -# -echo 2 > /proc/sys/net/ipv6/conf/{{ ifname }}/accept_ra - -# Autoconfigure addresses using Prefix Information in Router Advertisements. -echo 1 > /proc/sys/net/ipv6/conf/{{ ifname }}/autoconf -{% endif %} - -{% if dhcpv6_options is defined and dhcpv6_options.pd is defined %} -# Start wide dhcpv6 client -systemctl restart dhcp6c@{{ ifname }}.service -{% endif %} {% if default_route != 'none' %} # See https://phabricator.vyos.net/T2248 & T2220. Determine if we are enslaved diff --git a/data/templates/pppoe/peer.tmpl b/data/templates/pppoe/peer.tmpl index 0f78f9384..928ed1238 100644 --- a/data/templates/pppoe/peer.tmpl +++ b/data/templates/pppoe/peer.tmpl @@ -1,8 +1,5 @@ ### Autogenerated by interfaces-pppoe.py ### - -{% if description %} -# {{ description }} -{% endif %} +{{ '# ' ~ description if description is defined else '' }} # Require peer to provide the local IP address if it is not # specified explicitly in the config file. @@ -30,15 +27,21 @@ connect /bin/true noauth # Don't try to proxy ARP for the remote endpoint. User can set proxy -# arp entries up manually if they wish. More importantly, having +# arp entries up manually if they wish. More importantly, having # the "proxyarp" parameter set disables the "defaultroute" option. noproxyarp # Unlimited connection attempts maxfail 0 -plugin rp-pppoe.so -{{ source_interface }} +plugin rp-pppoe.so {{ source_interface }} +{% if access_concentrator is defined and access_concentrator is not none %} +rp_pppoe_ac '{{ access_concentrator }}' +{% endif %} +{% if service_name is defined and service_name is not none %} +rp_pppoe_service '{{ service_name }}' +{% endif %} + persist ifname {{ ifname }} ipparam {{ ifname }} @@ -54,14 +57,9 @@ mru {{ mtu }} {{ "usepeerdns" if no_peer_dns is not defined }} {% if ipv6 is defined %} -+ipv6 -{% if ipv6.address is defined and ipv6.address.autoconf is defined %} -ipv6cp-use-ipaddr -{% endif %} -{% endif %} - -{% if service_name is defined %} -rp_pppoe_service "{{ service_name }}" ++ipv6 {{ 'ipv6cp-use-ipaddr' if ipv6.address is defined and ipv6.address.autoconf is defined }} +{% else %} +noipv6 {% endif %} {% if connect_on_demand is defined %} @@ -71,8 +69,14 @@ demand # passed to the ip-up.d/ip-down.s scripts which is required for VRF support. {% if 'auto' in default_route %} defaultroute +{{ 'defaultroute6' if ipv6 is defined }} {% elif 'force' in default_route %} defaultroute replacedefaultroute +{{ 'defaultroute6' if ipv6 is defined }} {% endif %} +{% else %} +nodefaultroute +noreplacedefaultroute +{{ 'nodefaultroute6' if ipv6 is defined }} {% endif %} diff --git a/debian/control b/debian/control index c5cbeb7d4..f3a26e73e 100644 --- a/debian/control +++ b/debian/control @@ -156,6 +156,7 @@ Depends: traceroute, tuned, udp-broadcast-relay, + uidmap, usb-modeswitch, usbutils, vyatta-bash, diff --git a/debian/rules b/debian/rules index 70d39c481..c7a7138e1 100755 --- a/debian/rules +++ b/debian/rules @@ -18,6 +18,10 @@ DEB_TARGET_ARCH := $(shell dpkg-architecture -qDEB_TARGET_ARCH) %: dh $@ --with python3, --with quilt +# Skip dh_strip_nondeterminism - this is very time consuming +# and we have no non deterministic output (yet) +override_dh_strip_nondeterminism: + override_dh_gencontrol: dh_gencontrol -- -v$(shell (git describe --tags --long --match 'vyos/*' --dirty 2>/dev/null || echo 0.0-no.git.tag) | sed -E 's%vyos/%%' | sed -E 's%-dirty%+dirty%') diff --git a/debian/vyos-1x.install b/debian/vyos-1x.install index 2ed25755f..d332e0d36 100644 --- a/debian/vyos-1x.install +++ b/debian/vyos-1x.install @@ -3,6 +3,7 @@ etc/dhcp etc/ipsec.d etc/netplug etc/opennhrp +etc/ppp etc/rsyslog.d etc/securetty etc/security @@ -10,6 +11,7 @@ etc/sudoers.d etc/systemd etc/sysctl.d etc/udev +etc/update-motd.d etc/vyos lib/ opt/ diff --git a/interface-definitions/bcast-relay.xml.in b/interface-definitions/bcast-relay.xml.in index 1b354d885..c7948ded1 100644 --- a/interface-definitions/bcast-relay.xml.in +++ b/interface-definitions/bcast-relay.xml.in @@ -49,18 +49,7 @@ <multi/> </properties> </leafNode> - <leafNode name="port"> - <properties> - <help>Destination or source port to listen and retransmit on [REQUIRED]</help> - <valueHelp> - <format>u32:1-65535</format> - <description>UDP port to listen on</description> - </valueHelp> - <constraint> - <validator name="numeric" argument="--range 1-65535"/> - </constraint> - </properties> - </leafNode> + #include <include/port-number.xml.i> </children> </tagNode> </children> diff --git a/interface-definitions/containers.xml.in b/interface-definitions/containers.xml.in index 124b1f65e..d990e41a3 100644 --- a/interface-definitions/containers.xml.in +++ b/interface-definitions/containers.xml.in @@ -9,6 +9,10 @@ <tagNode name="name"> <properties> <help>Container name</help> + <constraint> + <regex>^[-a-zA-Z0-9]+$</regex> + </constraint> + <constraintErrorMessage>Container name must be alphanumeric and can contain hyphens</constraintErrorMessage> </properties> <children> <leafNode name="allow-host-networks"> @@ -17,14 +21,15 @@ <valueless/> </properties> </leafNode> - <leafNode name="description"> - <properties> - <help>Container description</help> - </properties> - </leafNode> + #include <include/generic-description.xml.i> + #include <include/generic-disable-node.xml.i> <tagNode name="environment"> <properties> <help>Add custom environment variables</help> + <constraint> + <regex>^[-_a-zA-Z0-9]+$</regex> + </constraint> + <constraintErrorMessage>Environment variable name must be alphanumeric and can contain hyphen and underscores</constraintErrorMessage> </properties> <children> <leafNode name="value"> @@ -43,6 +48,24 @@ <help>Image name in the hub-registry</help> </properties> </leafNode> + <leafNode name="memory"> + <properties> + <help>Constrain the memory available to a container (default: 512MB)</help> + <valueHelp> + <format>u32:0</format> + <description>Unlimited</description> + </valueHelp> + <valueHelp> + <format>u32:1-16384</format> + <description>Container memory in megabytes (MB)</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 0-16384"/> + </constraint> + <constraintErrorMessage>Container memory must be in range 0 to 16384 MB</constraintErrorMessage> + </properties> + <defaultValue>512</defaultValue> + </leafNode> <tagNode name="network"> <properties> <help>Attach user defined network to container</help> @@ -56,7 +79,7 @@ <help>Set IPv4 static address to container (optional)</help> <valueHelp> <format>ipv4</format> - <description>IPv4 address (x.x.x.1 reserved)</description> + <description>IPv4 address</description> </valueHelp> <constraint> <validator name="ipv4-address"/> @@ -115,6 +138,30 @@ </leafNode> </children> </tagNode> + <leafNode name="restart"> + <properties> + <help>Mount a volume into the container</help> + <completionHelp> + <list>no on-failure always</list> + </completionHelp> + <valueHelp> + <format>no</format> + <description>Do not restart containers on exit</description> + </valueHelp> + <valueHelp> + <format>on-failure</format> + <description>Restart containers when they exit with a non-zero exit code, retrying indefinitely (default)</description> + </valueHelp> + <valueHelp> + <format>always</format> + <description>Restart containers when they exit, regardless of status, retrying indefinitely</description> + </valueHelp> + <constraint> + <regex>^(no|on-failure|always)$</regex> + </constraint> + </properties> + <defaultValue>on-failure</defaultValue> + </leafNode> <tagNode name="volume"> <properties> <help>Mount a volume into the container</help> diff --git a/interface-definitions/firewall-options.xml.in b/interface-definitions/firewall-options.xml.in deleted file mode 100644 index 8d9225a9a..000000000 --- a/interface-definitions/firewall-options.xml.in +++ /dev/null @@ -1,50 +0,0 @@ -<?xml version="1.0"?> -<interfaceDefinition> - <node name="firewall"> - <children> - <node name="options"> - <properties> - <help>Firewall options/Packet manipulation</help> - <priority>990</priority> - </properties> - <children> - <tagNode name="interface" owner="${vyos_conf_scripts_dir}/firewall_options.py"> - <properties> - <help>Interface clamping options</help> - <completionHelp> - <script>${vyos_completion_dir}/list_interfaces.py</script> - </completionHelp> - </properties> - <children> - #include <include/generic-disable-node.xml.i> - <leafNode name="adjust-mss"> - <properties> - <help>Adjust MSS for IPv4 transit packets</help> - <valueHelp> - <format>500-1460</format> - <description>TCP Maximum segment size in bytes</description> - </valueHelp> - <constraint> - <validator name="numeric" argument="--range 500-1460"/> - </constraint> - </properties> - </leafNode> - <leafNode name="adjust-mss6"> - <properties> - <help>Adjust MSS for IPv6 transit packets</help> - <valueHelp> - <format>1280-1492</format> - <description>TCP Maximum segment size in bytes</description> - </valueHelp> - <constraint> - <validator name="numeric" argument="--range 1280-1492"/> - </constraint> - </properties> - </leafNode> - </children> - </tagNode> - </children> - </node> - </children> - </node> -</interfaceDefinition> diff --git a/interface-definitions/https.xml.in b/interface-definitions/https.xml.in index b65a89b56..b0532e249 100644 --- a/interface-definitions/https.xml.in +++ b/interface-definitions/https.xml.in @@ -1,7 +1,6 @@ <?xml version="1.0"?> <!-- HTTPS configuration --> <interfaceDefinition> - <syntaxVersion component='https' version='3'></syntaxVersion> <node name="service"> <children> <node name="https" owner="${vyos_conf_scripts_dir}/https.py"> diff --git a/interface-definitions/include/bgp/afi-export-import.xml.i b/interface-definitions/include/bgp/afi-export-import.xml.i new file mode 100644 index 000000000..86817cdb3 --- /dev/null +++ b/interface-definitions/include/bgp/afi-export-import.xml.i @@ -0,0 +1,41 @@ +<!-- include start from bgp/afi-export-import.xml.i --> +<node name="export"> + <properties> + <help>Export routes from this address-family</help> + </properties> + <children> + <leafNode name="vpn"> + <properties> + <help>to/from default instance VPN RIB</help> + <valueless/> + </properties> + </leafNode> + </children> +</node> +<node name="import"> + <properties> + <help>Import routes to this address-family</help> + </properties> + <children> + <leafNode name="vpn"> + <properties> + <help>to/from default instance VPN RIB</help> + <valueless/> + </properties> + </leafNode> + <leafNode name="vrf"> + <properties> + <help>VRF to import from</help> + <valueHelp> + <format>txt</format> + <description>VRF instance name</description> + </valueHelp> + <completionHelp> + <path>vrf name</path> + </completionHelp> + <multi/> + </properties> + </leafNode> + </children> +</node> +<!-- include end --> diff --git a/interface-definitions/include/bgp/afi-l2vpn-common.xml.i b/interface-definitions/include/bgp/afi-l2vpn-common.xml.i index aaa69e6c8..8deb189ab 100644 --- a/interface-definitions/include/bgp/afi-l2vpn-common.xml.i +++ b/interface-definitions/include/bgp/afi-l2vpn-common.xml.i @@ -12,5 +12,47 @@ </properties> </leafNode> #include <include/bgp/route-distinguisher.xml.i> -#include <include/bgp/route-target.xml.i> +<node name="route-target"> + <properties> + <help>Route Target</help> + </properties> + <children> + <leafNode name="both"> + <properties> + <help>Route Target both import and export</help> + <valueHelp> + <format>txt</format> + <description>Route target (A.B.C.D:MN|EF:OPQR|GHJK:MN)</description> + </valueHelp> + <constraint> + <validator name="bgp-route-target" argument="--single"/> + </constraint> + </properties> + </leafNode> + <leafNode name="import"> + <properties> + <help>Route Target import</help> + <valueHelp> + <format>txt</format> + <description>Route target (A.B.C.D:MN|EF:OPQR|GHJK:MN)</description> + </valueHelp> + <constraint> + <validator name="bgp-route-target" argument="--single"/> + </constraint> + </properties> + </leafNode> + <leafNode name="export"> + <properties> + <help>Route Target export</help> + <valueHelp> + <format>txt</format> + <description>Route target (A.B.C.D:MN|EF:OPQR|GHJK:MN)</description> + </valueHelp> + <constraint> + <validator name="bgp-route-target" argument="--single"/> + </constraint> + </properties> + </leafNode> + </children> +</node> <!-- include end --> diff --git a/interface-definitions/include/bgp/afi-label.xml.i b/interface-definitions/include/bgp/afi-label.xml.i new file mode 100644 index 000000000..f7a1f609f --- /dev/null +++ b/interface-definitions/include/bgp/afi-label.xml.i @@ -0,0 +1,36 @@ +<!-- include start from bgp/afi-label.xml.i --> +<node name="label"> + <properties> + <help>Label value for VRF</help> + </properties> + <children> + <node name="vpn"> + <properties> + <help>Between current address-family and VPN</help> + </properties> + <children> + <leafNode name="export"> + <properties> + <help>For routes leaked from current address-family to VPN</help> + <completionHelp> + <list>auto</list> + </completionHelp> + <valueHelp> + <format>auto</format> + <description>Automatically assign a label</description> + </valueHelp> + <valueHelp> + <format>u32:0-1048575</format> + <description>Label Value</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 0-1048575"/> + <regex>^(auto)$</regex> + </constraint> + </properties> + </leafNode> + </children> + </node> + </children> +</node> +<!-- include end --> diff --git a/interface-definitions/include/bgp/afi-path-limit.xml.i b/interface-definitions/include/bgp/afi-path-limit.xml.i new file mode 100644 index 000000000..e3d630a57 --- /dev/null +++ b/interface-definitions/include/bgp/afi-path-limit.xml.i @@ -0,0 +1,14 @@ +<!-- include start from bgp/afi-path-limit.xml.i --> +<leafNode name="path-limit"> + <properties> + <help>AS-path hopcount limit</help> + <valueHelp> + <format>u32:0-255</format> + <description>AS path hop count limit</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 0-255"/> + </constraint> + </properties> +</leafNode> +<!-- include end --> diff --git a/interface-definitions/include/bgp/afi-rd.xml.i b/interface-definitions/include/bgp/afi-rd.xml.i new file mode 100644 index 000000000..c4d29268c --- /dev/null +++ b/interface-definitions/include/bgp/afi-rd.xml.i @@ -0,0 +1,28 @@ +<!-- include start from bgp/afi-rd.xml.i --> +<node name="rd"> + <properties> + <help>Specify route distinguisher</help> + </properties> + <children> + <node name="vpn"> + <properties> + <help>Between current address-family and VPN</help> + </properties> + <children> + <leafNode name="export"> + <properties> + <help>For routes leaked from current address-family to VPN</help> + <valueHelp> + <format>ASN:NN_OR_IP-ADDRESS:NN</format> + <description>Route Distinguisher, (x.x.x.x:yyy|xxxx:yyyy)</description> + </valueHelp> + <constraint> + <regex>^((25[0-5]|2[0-4][0-9]|[1][0-9][0-9]|[1-9][0-9]|[0-9]?)(\.(25[0-5]|2[0-4][0-9]|[1][0-9][0-9]|[1-9][0-9]|[0-9]?)){3}|[0-9]{1,10}):[0-9]{1,5}$</regex> + </constraint> + </properties> + </leafNode> + </children> + </node> + </children> +</node> +<!-- include end --> diff --git a/interface-definitions/include/bgp/afi-route-map-export-import.xml.i b/interface-definitions/include/bgp/afi-route-map-export-import.xml.i new file mode 100644 index 000000000..eae10d312 --- /dev/null +++ b/interface-definitions/include/bgp/afi-route-map-export-import.xml.i @@ -0,0 +1,34 @@ +<!-- include start from bgp/afi-route-map.xml.i --> +<leafNode name="export"> + <properties> + <help>Route-map to filter outgoing route updates</help> + <completionHelp> + <path>policy route-map</path> + </completionHelp> + <valueHelp> + <format>txt</format> + <description>Route map name</description> + </valueHelp> + <constraint> + <regex>^[-_a-zA-Z0-9.]+$</regex> + </constraint> + <constraintErrorMessage>Name of route-map can only contain alpha-numeric letters, hyphen and underscores</constraintErrorMessage> + </properties> +</leafNode> +<leafNode name="import"> + <properties> + <help>Route-map to filter incoming route updates</help> + <completionHelp> + <path>policy route-map</path> + </completionHelp> + <valueHelp> + <format>txt</format> + <description>Route map name</description> + </valueHelp> + <constraint> + <regex>^[-_a-zA-Z0-9.]+$</regex> + </constraint> + <constraintErrorMessage>Name of route-map can only contain alpha-numeric letters, hyphen and underscores</constraintErrorMessage> + </properties> +</leafNode> +<!-- include end --> diff --git a/interface-definitions/include/bgp/afi-route-map-vpn.xml.i b/interface-definitions/include/bgp/afi-route-map-vpn.xml.i new file mode 100644 index 000000000..e6be113c5 --- /dev/null +++ b/interface-definitions/include/bgp/afi-route-map-vpn.xml.i @@ -0,0 +1,17 @@ +<!-- include start from bgp/afi-route-map-vpn.xml.i --> +<node name="route-map"> + <properties> + <help>Route-map to filter route updates to/from this peer</help> + </properties> + <children> + <node name="vpn"> + <properties> + <help>Between current address-family and VPN</help> + </properties> + <children> + #include <include/bgp/afi-route-map-export-import.xml.i> + </children> + </node> + </children> +</node> +<!-- include end --> diff --git a/interface-definitions/include/bgp/afi-route-map.xml.i b/interface-definitions/include/bgp/afi-route-map.xml.i index 24a5ddd12..0b6178176 100644 --- a/interface-definitions/include/bgp/afi-route-map.xml.i +++ b/interface-definitions/include/bgp/afi-route-map.xml.i @@ -4,38 +4,7 @@ <help>Route-map to filter route updates to/from this peer</help> </properties> <children> - <leafNode name="export"> - <properties> - <help>Route-map to filter outgoing route updates</help> - <completionHelp> - <path>policy route-map</path> - </completionHelp> - <valueHelp> - <format>txt</format> - <description>Route map name</description> - </valueHelp> - <constraint> - <regex>^[-_a-zA-Z0-9.]+$</regex> - </constraint> - <constraintErrorMessage>Name of route-map can only contain alpha-numeric letters, hyphen and underscores</constraintErrorMessage> - </properties> - </leafNode> - <leafNode name="import"> - <properties> - <help>Route-map to filter incoming route updates</help> - <completionHelp> - <path>policy route-map</path> - </completionHelp> - <valueHelp> - <format>txt</format> - <description>Route map name</description> - </valueHelp> - <constraint> - <regex>^[-_a-zA-Z0-9.]+$</regex> - </constraint> - <constraintErrorMessage>Name of route-map can only contain alpha-numeric letters, hyphen and underscores</constraintErrorMessage> - </properties> - </leafNode> + #include <include/bgp/afi-route-map-export-import.xml.i> </children> </node> <!-- include end --> diff --git a/interface-definitions/include/bgp/afi-route-target-vpn.xml.i b/interface-definitions/include/bgp/afi-route-target-vpn.xml.i new file mode 100644 index 000000000..1dc184a02 --- /dev/null +++ b/interface-definitions/include/bgp/afi-route-target-vpn.xml.i @@ -0,0 +1,52 @@ +<!-- include start from bgp/route-target-both.xml.i --> +<node name="route-target"> + <properties> + <help>Specify route distinguisher</help> + </properties> + <children> + <node name="vpn"> + <properties> + <help>Between current address-family and VPN</help> + </properties> + <children> + <leafNode name="both"> + <properties> + <help>Route Target both import and export</help> + <valueHelp> + <format>txt</format> + <description>Space separated route target list (A.B.C.D:MN|EF:OPQR|GHJK:MN)</description> + </valueHelp> + <constraint> + <validator name="bgp-route-target" argument="--multi"/> + </constraint> + </properties> + </leafNode> + <leafNode name="import"> + <properties> + <help>Route Target import</help> + <valueHelp> + <format>txt</format> + <description>Space separated route target list (A.B.C.D:MN|EF:OPQR|GHJK:MN)</description> + </valueHelp> + <constraint> + <validator name="bgp-route-target" argument="--multi"/> + </constraint> + </properties> + </leafNode> + <leafNode name="export"> + <properties> + <help>Route Target export</help> + <valueHelp> + <format>txt</format> + <description>Space separated route target list (A.B.C.D:MN|EF:OPQR|GHJK:MN)</description> + </valueHelp> + <constraint> + <validator name="bgp-route-target" argument="--multi"/> + </constraint> + </properties> + </leafNode> + </children> + </node> + </children> +</node> +<!-- include end --> diff --git a/interface-definitions/include/bgp/protocol-common-config.xml.i b/interface-definitions/include/bgp/protocol-common-config.xml.i index 552e85aa4..2b22bac7d 100644 --- a/interface-definitions/include/bgp/protocol-common-config.xml.i +++ b/interface-definitions/include/bgp/protocol-common-config.xml.i @@ -93,6 +93,9 @@ </tagNode> </children> </node> + #include <include/bgp/afi-export-import.xml.i> + #include <include/bgp/afi-label.xml.i> + #include <include/bgp/afi-maximum-paths.xml.i> <tagNode name="network"> <properties> <help>BGP network</help> @@ -114,7 +117,9 @@ #include <include/route-map.xml.i> </children> </tagNode> - #include <include/bgp/afi-maximum-paths.xml.i> + #include <include/bgp/afi-rd.xml.i> + #include <include/bgp/afi-route-map-vpn.xml.i> + #include <include/bgp/afi-route-target-vpn.xml.i> <node name="redistribute"> <properties> <help>Redistribute routes from other protocols into BGP</help> @@ -478,6 +483,9 @@ </tagNode> </children> </node> + #include <include/bgp/afi-export-import.xml.i> + #include <include/bgp/afi-label.xml.i> + #include <include/bgp/afi-maximum-paths.xml.i> <tagNode name="network"> <properties> <help>BGP network</help> @@ -490,22 +498,13 @@ </constraint> </properties> <children> - <leafNode name="path-limit"> - <properties> - <help>AS-path hopcount limit</help> - <valueHelp> - <format>u32:0-255</format> - <description>AS path hop count limit</description> - </valueHelp> - <constraint> - <validator name="numeric" argument="--range 0-255"/> - </constraint> - </properties> - </leafNode> + #include <include/bgp/afi-path-limit.xml.i> #include <include/route-map.xml.i> </children> </tagNode> - #include <include/bgp/afi-maximum-paths.xml.i> + #include <include/bgp/afi-rd.xml.i> + #include <include/bgp/afi-route-map-vpn.xml.i> + #include <include/bgp/afi-route-target-vpn.xml.i> <node name="redistribute"> <properties> <help>Redistribute routes from other protocols into BGP</help> @@ -661,18 +660,7 @@ </constraint> </properties> <children> - <leafNode name="path-limit"> - <properties> - <help>AS-path hopcount limit</help> - <valueHelp> - <format>u32:0-255</format> - <description>AS path hop count limit</description> - </valueHelp> - <constraint> - <validator name="numeric" argument="--range 0-255"/> - </constraint> - </properties> - </leafNode> + #include <include/bgp/afi-path-limit.xml.i> #include <include/route-map.xml.i> </children> </tagNode> diff --git a/interface-definitions/include/bgp/route-distinguisher.xml.i b/interface-definitions/include/bgp/route-distinguisher.xml.i index fdfbe7076..6d0aa3ef1 100644 --- a/interface-definitions/include/bgp/route-distinguisher.xml.i +++ b/interface-definitions/include/bgp/route-distinguisher.xml.i @@ -3,7 +3,7 @@ <properties> <help>Route Distinguisher</help> <valueHelp> - <format>txt</format> + <format>ASN:NN_OR_IP-ADDRESS:NN</format> <description>Route Distinguisher, (x.x.x.x:yyy|xxxx:yyyy)</description> </valueHelp> <constraint> diff --git a/interface-definitions/include/bgp/route-target.xml.i b/interface-definitions/include/bgp/route-target.xml.i deleted file mode 100644 index 674b6db15..000000000 --- a/interface-definitions/include/bgp/route-target.xml.i +++ /dev/null @@ -1,45 +0,0 @@ -<!-- include start from bgp/route-target.xml.i --> -<node name="route-target"> - <properties> - <help>Route Target</help> - </properties> - <children> - <leafNode name="both"> - <properties> - <help>Route Target both import and export</help> - <valueHelp> - <format>txt</format> - <description>Route target (x.x.x.x:yyy|xxxx:yyyy)</description> - </valueHelp> - <constraint> - <regex>^((25[0-5]|2[0-4][0-9]|[1][0-9][0-9]|[1-9][0-9]|[0-9]?)(\.(25[0-5]|2[0-4][0-9]|[1][0-9][0-9]|[1-9][0-9]|[0-9]?)){3}|[0-9]{1,10}):[0-9]{1,5}$</regex> - </constraint> - </properties> - </leafNode> - <leafNode name="export"> - <properties> - <help>Route Target export</help> - <valueHelp> - <format>txt</format> - <description>Route target (x.x.x.x:yyy|xxxx:yyyy)</description> - </valueHelp> - <constraint> - <regex>^((25[0-5]|2[0-4][0-9]|[1][0-9][0-9]|[1-9][0-9]|[0-9]?)(\.(25[0-5]|2[0-4][0-9]|[1][0-9][0-9]|[1-9][0-9]|[0-9]?)){3}|[0-9]{1,10}):[0-9]{1,5}$</regex> - </constraint> - </properties> - </leafNode> - <leafNode name="import"> - <properties> - <help>Route Target import</help> - <valueHelp> - <format>txt</format> - <description>Route target (x.x.x.x:yyy|xxxx:yyyy)</description> - </valueHelp> - <constraint> - <regex>^((25[0-5]|2[0-4][0-9]|[1][0-9][0-9]|[1-9][0-9]|[0-9]?)(\.(25[0-5]|2[0-4][0-9]|[1][0-9][0-9]|[1-9][0-9]|[0-9]?)){3}|[0-9]{1,10}):[0-9]{1,5}$</regex> - </constraint> - </properties> - </leafNode> - </children> -</node> -<!-- include end --> diff --git a/interface-definitions/include/conntrack-module-disable.xml.i b/interface-definitions/include/conntrack-module-disable.xml.i deleted file mode 100644 index f891225e0..000000000 --- a/interface-definitions/include/conntrack-module-disable.xml.i +++ /dev/null @@ -1,8 +0,0 @@ -<!-- include start from conntrack-module-disable.xml.i --> -<leafNode name="disable"> - <properties> - <help>Disable connection tracking helper</help> - <valueless/> - </properties> -</leafNode> -<!-- include end --> diff --git a/interface-definitions/include/interface/adjust-mss.xml.i b/interface-definitions/include/interface/adjust-mss.xml.i new file mode 100644 index 000000000..57019f02c --- /dev/null +++ b/interface-definitions/include/interface/adjust-mss.xml.i @@ -0,0 +1,23 @@ +<!-- include start from interface/adjust-mss.xml.i --> +<!-- https://datatracker.ietf.org/doc/html/rfc6691 --> +<leafNode name="adjust-mss"> + <properties> + <help>Adjust TCP MSS value</help> + <completionHelp> + <list>clamp-mss-to-pmtu</list> + </completionHelp> + <valueHelp> + <format>clamp-mss-to-pmtu</format> + <description>Automatically sets the MSS to the proper value</description> + </valueHelp> + <valueHelp> + <format>u32:500-65535</format> + <description>TCP Maximum segment size in bytes</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 500-65535"/> + <regex>^(clamp-mss-to-pmtu)$</regex> + </constraint> + </properties> +</leafNode> +<!-- include end --> diff --git a/interface-definitions/include/interface/interface-arp-cache-timeout.xml.i b/interface-definitions/include/interface/arp-cache-timeout.xml.i index b269fecd8..3fb64f1ff 100644 --- a/interface-definitions/include/interface/interface-arp-cache-timeout.xml.i +++ b/interface-definitions/include/interface/arp-cache-timeout.xml.i @@ -1,4 +1,4 @@ -<!-- include start from interface/interface-arp-cache-timeout.xml.i --> +<!-- include start from interface/arp-cache-timeout.xml.i --> <leafNode name="arp-cache-timeout"> <properties> <help>ARP cache entry timeout in seconds</help> diff --git a/interface-definitions/include/interface/interface-description.xml.i b/interface-definitions/include/interface/description.xml.i index d618b50d2..8579cf7d1 100644 --- a/interface-definitions/include/interface/interface-description.xml.i +++ b/interface-definitions/include/interface/description.xml.i @@ -1,4 +1,4 @@ -<!-- include start from interface/interface-description.xml.i --> +<!-- include start from interface/description.xml.i --> <leafNode name="description"> <properties> <help>Interface specific description</help> diff --git a/interface-definitions/include/interface/interface-dial-on-demand.xml.i b/interface-definitions/include/interface/dial-on-demand.xml.i index 66edd9678..30e8c7e97 100644 --- a/interface-definitions/include/interface/interface-dial-on-demand.xml.i +++ b/interface-definitions/include/interface/dial-on-demand.xml.i @@ -1,4 +1,4 @@ -<!-- include start from interface/interface-dial-on-demand.xml.i --> +<!-- include start from interface/dial-on-demand.xml.i --> <leafNode name="connect-on-demand"> <properties> <help>Establishment connection automatically when traffic is sent</help> diff --git a/interface-definitions/include/interface/interface-disable-arp-filter.xml.i b/interface-definitions/include/interface/disable-arp-filter.xml.i index 49cddaf76..a69455d58 100644 --- a/interface-definitions/include/interface/interface-disable-arp-filter.xml.i +++ b/interface-definitions/include/interface/disable-arp-filter.xml.i @@ -1,4 +1,4 @@ -<!-- include start from interface/interface-disable-arp-filter.xml.i --> +<!-- include start from interface/disable-arp-filter.xml.i --> <leafNode name="disable-arp-filter"> <properties> <help>Disable ARP filter on this interface</help> diff --git a/interface-definitions/include/interface/disable-forwarding.xml.i b/interface-definitions/include/interface/disable-forwarding.xml.i new file mode 100644 index 000000000..45382ec95 --- /dev/null +++ b/interface-definitions/include/interface/disable-forwarding.xml.i @@ -0,0 +1,8 @@ +<!-- include start from interface/disable-forwarding.xml.i --> +<leafNode name="disable-forwarding"> + <properties> + <help>Disable IP forwarding on this interface</help> + <valueless/> + </properties> +</leafNode> +<!-- include end --> diff --git a/interface-definitions/include/interface/interface-disable-link-detect.xml.i b/interface-definitions/include/interface/disable-link-detect.xml.i index c528885b2..b101ec292 100644 --- a/interface-definitions/include/interface/interface-disable-link-detect.xml.i +++ b/interface-definitions/include/interface/disable-link-detect.xml.i @@ -1,4 +1,4 @@ -<!-- include start from interface/interface-disable-link-detect.xml.i --> +<!-- include start from interface/disable-link-detect.xml.i --> <leafNode name="disable-link-detect"> <properties> <help>Ignore link state changes</help> diff --git a/interface-definitions/include/interface/interface-disable.xml.i b/interface-definitions/include/interface/disable.xml.i index d90e6395b..b76bd3f53 100644 --- a/interface-definitions/include/interface/interface-disable.xml.i +++ b/interface-definitions/include/interface/disable.xml.i @@ -1,4 +1,4 @@ -<!-- include start from interface/interface-disable.xml.i --> +<!-- include start from interface/disable.xml.i --> <leafNode name="disable"> <properties> <help>Administratively disable interface</help> diff --git a/interface-definitions/include/interface/interface-eapol.xml.i b/interface-definitions/include/interface/eapol.xml.i index 270ec5b13..c4cdeae0c 100644 --- a/interface-definitions/include/interface/interface-eapol.xml.i +++ b/interface-definitions/include/interface/eapol.xml.i @@ -1,4 +1,4 @@ -<!-- include start from interface/interface-eapol.xml.i --> +<!-- include start from interface/eapol.xml.i --> <node name="eapol"> <properties> <help>Extensible Authentication Protocol over Local Area Network</help> diff --git a/interface-definitions/include/interface/interface-enable-arp-accept.xml.i b/interface-definitions/include/interface/enable-arp-accept.xml.i index 7c5d51857..90f6bc3db 100644 --- a/interface-definitions/include/interface/interface-enable-arp-accept.xml.i +++ b/interface-definitions/include/interface/enable-arp-accept.xml.i @@ -1,4 +1,4 @@ -<!-- include start from interface/interface-enable-arp-accept.xml.i --> +<!-- include start from interface/enable-arp-accept.xml.i --> <leafNode name="enable-arp-accept"> <properties> <help>Enable ARP accept on this interface</help> diff --git a/interface-definitions/include/interface/interface-enable-arp-announce.xml.i b/interface-definitions/include/interface/enable-arp-announce.xml.i index f44599c54..cf02fce0b 100644 --- a/interface-definitions/include/interface/interface-enable-arp-announce.xml.i +++ b/interface-definitions/include/interface/enable-arp-announce.xml.i @@ -1,4 +1,4 @@ -<!-- include start from interface/interface-enable-arp-announce.xml.i --> +<!-- include start from interface/enable-arp-announce.xml.i --> <leafNode name="enable-arp-announce"> <properties> <help>Enable ARP announce on this interface</help> diff --git a/interface-definitions/include/interface/interface-enable-arp-ignore.xml.i b/interface-definitions/include/interface/enable-arp-ignore.xml.i index 3ea39613c..5bb444f35 100644 --- a/interface-definitions/include/interface/interface-enable-arp-ignore.xml.i +++ b/interface-definitions/include/interface/enable-arp-ignore.xml.i @@ -1,4 +1,4 @@ -<!-- include start from interface/interface-enable-arp-ignore.xml.i --> +<!-- include start from interface/enable-arp-ignore.xml.i --> <leafNode name="enable-arp-ignore"> <properties> <help>Enable ARP ignore on this interface</help> diff --git a/interface-definitions/include/interface/interface-enable-proxy-arp.xml.i b/interface-definitions/include/interface/enable-proxy-arp.xml.i index dbdeeb7a7..27e497f84 100644 --- a/interface-definitions/include/interface/interface-enable-proxy-arp.xml.i +++ b/interface-definitions/include/interface/enable-proxy-arp.xml.i @@ -1,4 +1,4 @@ -<!-- include start from interface/interface-enable-proxy-arp.xml.i --> +<!-- include start from interface/enable-proxy-arp.xml.i --> <leafNode name="enable-proxy-arp"> <properties> <help>Enable proxy-arp on this interface</help> diff --git a/interface-definitions/include/interface/interface-hw-id.xml.i b/interface-definitions/include/interface/hw-id.xml.i index 989cd9cb7..a3a1eec7c 100644 --- a/interface-definitions/include/interface/interface-hw-id.xml.i +++ b/interface-definitions/include/interface/hw-id.xml.i @@ -1,4 +1,4 @@ -<!-- include start from interface/interface-hw-id.xml.i --> +<!-- include start from interface/hw-id.xml.i --> <leafNode name="hw-id"> <properties> <help>Associate Ethernet Interface with given Media Access Control (MAC) address</help> diff --git a/interface-definitions/include/interface/interface-disable-forwarding.xml.i b/interface-definitions/include/interface/interface-disable-forwarding.xml.i deleted file mode 100644 index cb6ef0475..000000000 --- a/interface-definitions/include/interface/interface-disable-forwarding.xml.i +++ /dev/null @@ -1,8 +0,0 @@ -<!-- include start from interface/interface-disable-forwarding.xml.i --> -<leafNode name="disable-forwarding"> - <properties> - <help>Disable IPv4 forwarding on this interface</help> - <valueless/> - </properties> -</leafNode> -<!-- include end --> diff --git a/interface-definitions/include/interface/interface-ipv4-options.xml.i b/interface-definitions/include/interface/interface-ipv4-options.xml.i deleted file mode 100644 index c2d0677b7..000000000 --- a/interface-definitions/include/interface/interface-ipv4-options.xml.i +++ /dev/null @@ -1,18 +0,0 @@ -<!-- include start from interface/interface-ipv4-options.xml.i --> -<node name="ip"> - <properties> - <help>IPv4 routing parameters</help> - </properties> - <children> - #include <include/interface/interface-arp-cache-timeout.xml.i> - #include <include/interface/interface-disable-arp-filter.xml.i> - #include <include/interface/interface-disable-forwarding.xml.i> - #include <include/interface/interface-enable-arp-accept.xml.i> - #include <include/interface/interface-enable-arp-announce.xml.i> - #include <include/interface/interface-enable-arp-ignore.xml.i> - #include <include/interface/interface-enable-proxy-arp.xml.i> - #include <include/interface/interface-proxy-arp-pvlan.xml.i> - #include <include/interface/interface-source-validation.xml.i> - </children> -</node> -<!-- include end --> diff --git a/interface-definitions/include/interface/ipv4-options.xml.i b/interface-definitions/include/interface/ipv4-options.xml.i new file mode 100644 index 000000000..bca1229c6 --- /dev/null +++ b/interface-definitions/include/interface/ipv4-options.xml.i @@ -0,0 +1,19 @@ +<!-- include start from interface/ipv4-options.xml.i --> +<node name="ip"> + <properties> + <help>IPv4 routing parameters</help> + </properties> + <children> + #include <include/interface/adjust-mss.xml.i> + #include <include/interface/arp-cache-timeout.xml.i> + #include <include/interface/disable-arp-filter.xml.i> + #include <include/interface/disable-forwarding.xml.i> + #include <include/interface/enable-arp-accept.xml.i> + #include <include/interface/enable-arp-announce.xml.i> + #include <include/interface/enable-arp-ignore.xml.i> + #include <include/interface/enable-proxy-arp.xml.i> + #include <include/interface/proxy-arp-pvlan.xml.i> + #include <include/interface/source-validation.xml.i> + </children> +</node> +<!-- include end --> diff --git a/interface-definitions/include/interface/ipv6-disable-forwarding.xml.i b/interface-definitions/include/interface/ipv6-disable-forwarding.xml.i deleted file mode 100644 index 4adb77d1b..000000000 --- a/interface-definitions/include/interface/ipv6-disable-forwarding.xml.i +++ /dev/null @@ -1,8 +0,0 @@ -<!-- include start from interface/ipv6-disable-forwarding.xml.i --> -<leafNode name="disable-forwarding"> - <properties> - <help>Disable IPv6 forwarding on this interface</help> - <valueless/> - </properties> -</leafNode> -<!-- include end --> diff --git a/interface-definitions/include/interface/interface-ipv6-options.xml.i b/interface-definitions/include/interface/ipv6-options.xml.i index dcd5a8710..f740ce0c2 100644 --- a/interface-definitions/include/interface/interface-ipv6-options.xml.i +++ b/interface-definitions/include/interface/ipv6-options.xml.i @@ -1,11 +1,12 @@ -<!-- include start from interface/interface-ipv6-options.xml.i --> +<!-- include start from interface/ipv6-options.xml.i --> <node name="ipv6"> <properties> <help>IPv6 routing parameters</help> </properties> <children> + #include <include/interface/adjust-mss.xml.i> + #include <include/interface/disable-forwarding.xml.i> #include <include/interface/ipv6-address.xml.i> - #include <include/interface/ipv6-disable-forwarding.xml.i> #include <include/interface/ipv6-dup-addr-detect-transmits.xml.i> </children> </node> diff --git a/interface-definitions/include/interface/interface-mac.xml.i b/interface-definitions/include/interface/mac.xml.i index d7107ad23..705330dce 100644 --- a/interface-definitions/include/interface/interface-mac.xml.i +++ b/interface-definitions/include/interface/mac.xml.i @@ -1,4 +1,4 @@ -<!-- include start from interface/interface-mac.xml.i --> +<!-- include start from interface/mac.xml.i --> <leafNode name="mac"> <properties> <help>Media Access Control (MAC) address</help> diff --git a/interface-definitions/include/interface/interface-mirror.xml.i b/interface-definitions/include/interface/mirror.xml.i index b3b45fb43..2959551f0 100644 --- a/interface-definitions/include/interface/interface-mirror.xml.i +++ b/interface-definitions/include/interface/mirror.xml.i @@ -1,4 +1,4 @@ -<!-- include start from interface/interface-mirror.xml.i --> +<!-- include start from interface/mirror.xml.i --> <node name="mirror"> <properties> <help>Incoming/outgoing packet mirroring destination</help> diff --git a/interface-definitions/include/interface/interface-mtu-1200-16000.xml.i b/interface-definitions/include/interface/mtu-1200-16000.xml.i index 3241ba912..ccd986d55 100644 --- a/interface-definitions/include/interface/interface-mtu-1200-16000.xml.i +++ b/interface-definitions/include/interface/mtu-1200-16000.xml.i @@ -1,4 +1,4 @@ -<!-- include start from interface/interface-mtu-1200-16000.xml.i --> +<!-- include start from interface/mtu-1200-16000.xml.i --> <leafNode name="mtu"> <properties> <help>Maximum Transmission Unit (MTU)</help> diff --git a/interface-definitions/include/interface/interface-mtu-1450-16000.xml.i b/interface-definitions/include/interface/mtu-1450-16000.xml.i index 0a35bbbaa..2dc3a2029 100644 --- a/interface-definitions/include/interface/interface-mtu-1450-16000.xml.i +++ b/interface-definitions/include/interface/mtu-1450-16000.xml.i @@ -1,4 +1,4 @@ -<!-- include start from interface/interface-mtu-1450-16000.xml.i --> +<!-- include start from interface/mtu-1450-16000.xml.i --> <leafNode name="mtu"> <properties> <help>Maximum Transmission Unit (MTU)</help> diff --git a/interface-definitions/include/interface/interface-mtu-64-8024.xml.i b/interface-definitions/include/interface/mtu-64-8024.xml.i index f75de02ba..9b8bc4697 100644 --- a/interface-definitions/include/interface/interface-mtu-64-8024.xml.i +++ b/interface-definitions/include/interface/mtu-64-8024.xml.i @@ -1,4 +1,4 @@ -<!-- include start from interface/interface-mtu-68-8024.xml.i --> +<!-- include start from interface/mtu-68-8024.xml.i --> <leafNode name="mtu"> <properties> <help>Maximum Transmission Unit (MTU)</help> diff --git a/interface-definitions/include/interface/interface-mtu-68-1500.xml.i b/interface-definitions/include/interface/mtu-68-1500.xml.i index 9e6fe8760..e3b70302f 100644 --- a/interface-definitions/include/interface/interface-mtu-68-1500.xml.i +++ b/interface-definitions/include/interface/mtu-68-1500.xml.i @@ -1,4 +1,4 @@ -<!-- include start from interface/interface-mtu-68-1500.xml.i --> +<!-- include start from interface/mtu-68-1500.xml.i --> <leafNode name="mtu"> <properties> <help>Maximum Transmission Unit (MTU)</help> diff --git a/interface-definitions/include/interface/interface-mtu-68-16000.xml.i b/interface-definitions/include/interface/mtu-68-16000.xml.i index 83af7bbd4..b610ab3e2 100644 --- a/interface-definitions/include/interface/interface-mtu-68-16000.xml.i +++ b/interface-definitions/include/interface/mtu-68-16000.xml.i @@ -1,4 +1,4 @@ -<!-- include start from interface/interface-mtu-68-16000.xml.i --> +<!-- include start from interface/mtu-68-16000.xml.i --> <leafNode name="mtu"> <properties> <help>Maximum Transmission Unit (MTU)</help> diff --git a/interface-definitions/include/interface/interface-parameters-dont-fragment.xml.i b/interface-definitions/include/interface/parameters-dont-fragment.xml.i index 166c31115..d34f0a97b 100644 --- a/interface-definitions/include/interface/interface-parameters-dont-fragment.xml.i +++ b/interface-definitions/include/interface/parameters-dont-fragment.xml.i @@ -1,4 +1,4 @@ -<!-- include start from interface/interface-parameters-df.xml.i --> +<!-- include start from interface/parameters-df.xml.i --> <leafNode name="dont-fragment"> <properties> <help>Specifies the usage of the dont fragment (DF) bit</help> diff --git a/interface-definitions/include/interface/interface-parameters-flowlabel.xml.i b/interface-definitions/include/interface/parameters-flowlabel.xml.i index ed075e40d..7fa571634 100644 --- a/interface-definitions/include/interface/interface-parameters-flowlabel.xml.i +++ b/interface-definitions/include/interface/parameters-flowlabel.xml.i @@ -1,4 +1,4 @@ -<!-- include start from interface/interface-parameters-flowlabel.xml.i --> +<!-- include start from interface/parameters-flowlabel.xml.i --> <leafNode name="flowlabel"> <properties> <help>Specifies the flow label to use in outgoing packets</help> diff --git a/interface-definitions/include/interface/interface-parameters-key.xml.i b/interface-definitions/include/interface/parameters-key.xml.i index 6c59f7879..25a6c0303 100644 --- a/interface-definitions/include/interface/interface-parameters-key.xml.i +++ b/interface-definitions/include/interface/parameters-key.xml.i @@ -1,4 +1,4 @@ -<!-- include start from interface/interface-parameters-key.xml.i --> +<!-- include start from interface/parameters-key.xml.i --> <leafNode name="key"> <properties> <help>Tunnel key (only GRE tunnels)</help> diff --git a/interface-definitions/include/interface/interface-parameters-tos.xml.i b/interface-definitions/include/interface/parameters-tos.xml.i index 83b4e0671..83b4e0671 100644 --- a/interface-definitions/include/interface/interface-parameters-tos.xml.i +++ b/interface-definitions/include/interface/parameters-tos.xml.i diff --git a/interface-definitions/include/interface/interface-parameters-ttl.xml.i b/interface-definitions/include/interface/parameters-ttl.xml.i index df193cf24..da5ce69c2 100644 --- a/interface-definitions/include/interface/interface-parameters-ttl.xml.i +++ b/interface-definitions/include/interface/parameters-ttl.xml.i @@ -1,4 +1,4 @@ -<!-- include start from interface/interface-parameters-ttl.xml.i --> +<!-- include start from interface/parameters-ttl.xml.i --> <leafNode name="ttl"> <properties> <help>Specifies TTL value to use in outgoing packets</help> diff --git a/interface-definitions/include/interface/interface-proxy-arp-pvlan.xml.i b/interface-definitions/include/interface/proxy-arp-pvlan.xml.i index 153dfc072..c00b2fe85 100644 --- a/interface-definitions/include/interface/interface-proxy-arp-pvlan.xml.i +++ b/interface-definitions/include/interface/proxy-arp-pvlan.xml.i @@ -1,4 +1,4 @@ -<!-- include start from interface/interface-proxy-arp-pvlan.xml.i --> +<!-- include start from interface/proxy-arp-pvlan.xml.i --> <leafNode name="proxy-arp-pvlan"> <properties> <help>Enable private VLAN proxy ARP on this interface</help> diff --git a/interface-definitions/include/interface/interface-source-validation.xml.i b/interface-definitions/include/interface/source-validation.xml.i index 70914f2e9..f38065f4d 100644 --- a/interface-definitions/include/interface/interface-source-validation.xml.i +++ b/interface-definitions/include/interface/source-validation.xml.i @@ -1,4 +1,4 @@ -<!-- include start from interface/interface-source-validation.xml.i --> +<!-- include start from interface/source-validation.xml.i --> <leafNode name="source-validation"> <properties> <help>Source validation by reversed path (RFC3704)</help> diff --git a/interface-definitions/include/interface/vif-s.xml.i b/interface-definitions/include/interface/vif-s.xml.i index 17d1746be..3fd69d9d1 100644 --- a/interface-definitions/include/interface/vif-s.xml.i +++ b/interface-definitions/include/interface/vif-s.xml.i @@ -9,11 +9,11 @@ </properties> <children> #include <include/interface/address-ipv4-ipv6-dhcp.xml.i> - #include <include/interface/interface-description.xml.i> + #include <include/interface/description.xml.i> #include <include/interface/dhcp-options.xml.i> #include <include/interface/dhcpv6-options.xml.i> - #include <include/interface/interface-disable-link-detect.xml.i> - #include <include/interface/interface-disable.xml.i> + #include <include/interface/disable-link-detect.xml.i> + #include <include/interface/disable.xml.i> <leafNode name="protocol"> <properties> <help>Protocol used for service VLAN (default: 802.1ad)</help> @@ -35,10 +35,10 @@ </properties> <defaultValue>802.1ad</defaultValue> </leafNode> - #include <include/interface/interface-ipv4-options.xml.i> - #include <include/interface/interface-ipv6-options.xml.i> - #include <include/interface/interface-mac.xml.i> - #include <include/interface/interface-mtu-68-16000.xml.i> + #include <include/interface/ipv4-options.xml.i> + #include <include/interface/ipv6-options.xml.i> + #include <include/interface/mac.xml.i> + #include <include/interface/mtu-68-16000.xml.i> <tagNode name="vif-c"> <properties> <help>QinQ TAG-C Virtual Local Area Network (VLAN) ID</help> @@ -49,19 +49,19 @@ </properties> <children> #include <include/interface/address-ipv4-ipv6-dhcp.xml.i> - #include <include/interface/interface-description.xml.i> + #include <include/interface/description.xml.i> #include <include/interface/dhcp-options.xml.i> #include <include/interface/dhcpv6-options.xml.i> - #include <include/interface/interface-disable-link-detect.xml.i> - #include <include/interface/interface-disable.xml.i> - #include <include/interface/interface-ipv4-options.xml.i> - #include <include/interface/interface-ipv6-options.xml.i> - #include <include/interface/interface-mac.xml.i> - #include <include/interface/interface-mtu-68-16000.xml.i> - #include <include/interface/interface-vrf.xml.i> + #include <include/interface/disable-link-detect.xml.i> + #include <include/interface/disable.xml.i> + #include <include/interface/ipv4-options.xml.i> + #include <include/interface/ipv6-options.xml.i> + #include <include/interface/mac.xml.i> + #include <include/interface/mtu-68-16000.xml.i> + #include <include/interface/vrf.xml.i> </children> </tagNode> - #include <include/interface/interface-vrf.xml.i> + #include <include/interface/vrf.xml.i> </children> </tagNode> <!-- include end --> diff --git a/interface-definitions/include/interface/vif.xml.i b/interface-definitions/include/interface/vif.xml.i index 9e89cbbf6..8daafeaf4 100644 --- a/interface-definitions/include/interface/vif.xml.i +++ b/interface-definitions/include/interface/vif.xml.i @@ -13,12 +13,12 @@ </properties> <children> #include <include/interface/address-ipv4-ipv6-dhcp.xml.i> - #include <include/interface/interface-description.xml.i> + #include <include/interface/description.xml.i> #include <include/interface/dhcp-options.xml.i> #include <include/interface/dhcpv6-options.xml.i> - #include <include/interface/interface-disable-link-detect.xml.i> - #include <include/interface/interface-disable.xml.i> - #include <include/interface/interface-vrf.xml.i> + #include <include/interface/disable-link-detect.xml.i> + #include <include/interface/disable.xml.i> + #include <include/interface/vrf.xml.i> <leafNode name="egress-qos"> <properties> <help>VLAN egress QoS</help> @@ -45,10 +45,10 @@ <constraintErrorMessage>QoS mapping should be in the format of '0:7 2:3' with numbers 0-9</constraintErrorMessage> </properties> </leafNode> - #include <include/interface/interface-ipv4-options.xml.i> - #include <include/interface/interface-ipv6-options.xml.i> - #include <include/interface/interface-mac.xml.i> - #include <include/interface/interface-mtu-68-16000.xml.i> + #include <include/interface/ipv4-options.xml.i> + #include <include/interface/ipv6-options.xml.i> + #include <include/interface/mac.xml.i> + #include <include/interface/mtu-68-16000.xml.i> </children> </tagNode> <!-- include end --> diff --git a/interface-definitions/include/interface/interface-vrf.xml.i b/interface-definitions/include/interface/vrf.xml.i index ef6ca1241..5ad978a27 100644 --- a/interface-definitions/include/interface/interface-vrf.xml.i +++ b/interface-definitions/include/interface/vrf.xml.i @@ -1,4 +1,4 @@ -<!-- include start from interface/interface-vrf.xml.i --> +<!-- include start from interface/vrf.xml.i --> <leafNode name="vrf"> <properties> <help>VRF instance name</help> diff --git a/interface-definitions/include/interface/interface-xdp.xml.i b/interface-definitions/include/interface/xdp.xml.i index 0253f6dad..10223e766 100644 --- a/interface-definitions/include/interface/interface-xdp.xml.i +++ b/interface-definitions/include/interface/xdp.xml.i @@ -1,4 +1,4 @@ -<!-- include start from interface/interface-xdp.xml.i --> +<!-- include start from interface/xdp.xml.i --> <leafNode name="xdp"> <properties> <help>Enable eXpress Data Path</help> diff --git a/interface-definitions/include/isis/protocol-common-config.xml.i b/interface-definitions/include/isis/protocol-common-config.xml.i index af5a21f49..84e2f7bb2 100644 --- a/interface-definitions/include/isis/protocol-common-config.xml.i +++ b/interface-definitions/include/isis/protocol-common-config.xml.i @@ -447,7 +447,7 @@ <help>Border Gateway Protocol (BGP)</help> </properties> <children> - #include <include/isis/redistribute-ipv4.xml.i> + #include <include/isis/redistribute-level-1-2.xml.i> </children> </node> <node name="connected"> @@ -455,7 +455,7 @@ <help>Redistribute connected routes into IS-IS</help> </properties> <children> - #include <include/isis/redistribute-ipv4.xml.i> + #include <include/isis/redistribute-level-1-2.xml.i> </children> </node> <node name="kernel"> @@ -463,7 +463,7 @@ <help>Redistribute kernel routes into IS-IS</help> </properties> <children> - #include <include/isis/redistribute-ipv4.xml.i> + #include <include/isis/redistribute-level-1-2.xml.i> </children> </node> <node name="ospf"> @@ -471,7 +471,7 @@ <help>Redistribute OSPF routes into IS-IS</help> </properties> <children> - #include <include/isis/redistribute-ipv4.xml.i> + #include <include/isis/redistribute-level-1-2.xml.i> </children> </node> <node name="rip"> @@ -479,7 +479,7 @@ <help>Redistribute RIP routes into IS-IS</help> </properties> <children> - #include <include/isis/redistribute-ipv4.xml.i> + #include <include/isis/redistribute-level-1-2.xml.i> </children> </node> <node name="static"> @@ -487,7 +487,7 @@ <help>Redistribute static routes into IS-IS</help> </properties> <children> - #include <include/isis/redistribute-ipv4.xml.i> + #include <include/isis/redistribute-level-1-2.xml.i> </children> </node> </children> @@ -502,7 +502,7 @@ <help>Redistribute BGP routes into IS-IS</help> </properties> <children> - #include <include/isis/redistribute-ipv6.xml.i> + #include <include/isis/redistribute-level-1-2.xml.i> </children> </node> <node name="connected"> @@ -510,7 +510,7 @@ <help>Redistribute connected routes into IS-IS</help> </properties> <children> - #include <include/isis/redistribute-ipv6.xml.i> + #include <include/isis/redistribute-level-1-2.xml.i> </children> </node> <node name="kernel"> @@ -518,7 +518,7 @@ <help>Redistribute kernel routes into IS-IS</help> </properties> <children> - #include <include/isis/redistribute-ipv6.xml.i> + #include <include/isis/redistribute-level-1-2.xml.i> </children> </node> <node name="ospf6"> @@ -526,7 +526,7 @@ <help>Redistribute OSPFv3 routes into IS-IS</help> </properties> <children> - #include <include/isis/redistribute-ipv6.xml.i> + #include <include/isis/redistribute-level-1-2.xml.i> </children> </node> <node name="ripng"> @@ -534,7 +534,7 @@ <help>Redistribute RIPng routes into IS-IS</help> </properties> <children> - #include <include/isis/redistribute-ipv6.xml.i> + #include <include/isis/redistribute-level-1-2.xml.i> </children> </node> <node name="static"> @@ -542,7 +542,7 @@ <help>Redistribute static routes into IS-IS</help> </properties> <children> - #include <include/isis/redistribute-ipv6.xml.i> + #include <include/isis/redistribute-level-1-2.xml.i> </children> </node> </children> diff --git a/interface-definitions/include/isis/redistribute-ipv4.xml.i b/interface-definitions/include/isis/redistribute-ipv4.xml.i deleted file mode 100644 index fbb6210c7..000000000 --- a/interface-definitions/include/isis/redistribute-ipv4.xml.i +++ /dev/null @@ -1,42 +0,0 @@ -<!-- include start from isis/redistribute-ipv4.xml.i --> -<node name="level-1"> - <properties> - <help>Redistribute into level-1</help> - </properties> - <children> - <leafNode name="metric"> - <properties> - <help>Metric for redistributed routes</help> - <valueHelp> - <format>u32:0-16777215</format> - <description>ISIS default metric</description> - </valueHelp> - <constraint> - <validator name="numeric" argument="--range 0-16777215"/> - </constraint> - </properties> - </leafNode> - #include <include/route-map.xml.i> - </children> -</node> -<node name="level-2"> - <properties> - <help>Redistribute into level-2</help> - </properties> - <children> - <leafNode name="metric"> - <properties> - <help>Metric for redistributed routes</help> - <valueHelp> - <format>u32:0-16777215</format> - <description>ISIS default metric</description> - </valueHelp> - <constraint> - <validator name="numeric" argument="--range 0-16777215"/> - </constraint> - </properties> - </leafNode> - #include <include/route-map.xml.i> - </children> -</node> -<!-- include end --> diff --git a/interface-definitions/include/isis/redistribute-ipv6.xml.i b/interface-definitions/include/isis/redistribute-ipv6.xml.i deleted file mode 100644 index 7e679e38a..000000000 --- a/interface-definitions/include/isis/redistribute-ipv6.xml.i +++ /dev/null @@ -1,42 +0,0 @@ -<!-- include start from isis/redistribute-ipv6.xml.i --> -<node name="level-1"> - <properties> - <help>Redistribute into level-1</help> - </properties> - <children> - <leafNode name="metric"> - <properties> - <help>Metric for redistributed routes</help> - <valueHelp> - <format>u32:0-16777215</format> - <description>ISIS default metric</description> - </valueHelp> - <constraint> - <validator name="numeric" argument="--range 0-16777215"/> - </constraint> - </properties> - </leafNode> - #include <include/route-map.xml.i> - </children> -</node> -<node name="level-2"> - <properties> - <help>Redistribute into level-2</help> - </properties> - <children> - <leafNode name="metric"> - <properties> - <help>Metric for redistributed routes</help> - <valueHelp> - <format>u32:0-16777215</format> - <description>ISIS default metric</description> - </valueHelp> - <constraint> - <validator name="numeric" argument="--range 0-16777215"/> - </constraint> - </properties> - </leafNode> - #include <include/route-map.xml.i> - </children> -</node> -<!-- include end -->
\ No newline at end of file diff --git a/interface-definitions/include/isis/redistribute-level-1-2.xml.i b/interface-definitions/include/isis/redistribute-level-1-2.xml.i new file mode 100644 index 000000000..abb85274f --- /dev/null +++ b/interface-definitions/include/isis/redistribute-level-1-2.xml.i @@ -0,0 +1,20 @@ +<!-- include start from isis/redistribute-level-1-2.xml.i --> +<node name="level-1"> + <properties> + <help>Redistribute into level-1</help> + </properties> + <children> + #include <include/isis/metric.xml.i> + #include <include/route-map.xml.i> + </children> +</node> +<node name="level-2"> + <properties> + <help>Redistribute into level-2</help> + </properties> + <children> + #include <include/isis/metric.xml.i> + #include <include/route-map.xml.i> + </children> +</node> +<!-- 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 db39b1a86..c4ca613a4 100644 --- a/interface-definitions/include/ospf/protocol-common-config.xml.i +++ b/interface-definitions/include/ospf/protocol-common-config.xml.i @@ -361,6 +361,23 @@ </constraint> </properties> <children> + <leafNode name="area"> + <properties> + <help>Enable OSPF on this interface</help> + <valueHelp> + <format>u32</format> + <description>OSPF area ID as decimal notation</description> + </valueHelp> + <valueHelp> + <format>ipv4</format> + <description>OSPF area ID in IP address notation</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 0-4294967295"/> + <validator name="ip-address"/> + </constraint> + </properties> + </leafNode> #include <include/ospf/authentication.xml.i> #include <include/ospf/intervals.xml.i> #include <include/ospf/interface-common.xml.i> diff --git a/interface-definitions/include/port-number.xml.i b/interface-definitions/include/port-number.xml.i index b62aef32b..6820df0c4 100644 --- a/interface-definitions/include/port-number.xml.i +++ b/interface-definitions/include/port-number.xml.i @@ -9,6 +9,7 @@ <constraint> <validator name="numeric" argument="--range 1-65535"/> </constraint> + <constraintErrorMessage>Port number must be in range 1 to 65535</constraintErrorMessage> </properties> </leafNode> <!-- include end --> diff --git a/interface-definitions/include/pppoe-access-concentrator.xml.i b/interface-definitions/include/pppoe-access-concentrator.xml.i new file mode 100644 index 000000000..ccfcc1c49 --- /dev/null +++ b/interface-definitions/include/pppoe-access-concentrator.xml.i @@ -0,0 +1,11 @@ +<!-- include start from pppoe-access-concentrator.xml.i --> +<leafNode name="access-concentrator"> + <properties> + <help>Access concentrator name</help> + <constraint> + <regex>[a-zA-Z0-9]{1,100}</regex> + </constraint> + <constraintErrorMessage>Access-concentrator name must be alphanumerical only (max. 100 characters)</constraintErrorMessage> + </properties> +</leafNode> +<!-- include end --> diff --git a/interface-definitions/interfaces-bonding.xml.in b/interface-definitions/interfaces-bonding.xml.in index 4bfc6e730..05e0d8461 100644 --- a/interface-definitions/interfaces-bonding.xml.in +++ b/interface-definitions/interfaces-bonding.xml.in @@ -49,13 +49,13 @@ </leafNode> </children> </node> - #include <include/interface/interface-description.xml.i> + #include <include/interface/description.xml.i> #include <include/interface/dhcp-options.xml.i> #include <include/interface/dhcpv6-options.xml.i> - #include <include/interface/interface-disable-link-detect.xml.i> - #include <include/interface/interface-disable.xml.i> - #include <include/interface/interface-vrf.xml.i> - #include <include/interface/interface-mirror.xml.i> + #include <include/interface/disable-link-detect.xml.i> + #include <include/interface/disable.xml.i> + #include <include/interface/vrf.xml.i> + #include <include/interface/mirror.xml.i> <leafNode name="hash-policy"> <properties> <help>Bonding transmit hash policy</help> @@ -89,9 +89,9 @@ </properties> <defaultValue>layer2</defaultValue> </leafNode> - #include <include/interface/interface-ipv4-options.xml.i> - #include <include/interface/interface-ipv6-options.xml.i> - #include <include/interface/interface-mac.xml.i> + #include <include/interface/ipv4-options.xml.i> + #include <include/interface/ipv6-options.xml.i> + #include <include/interface/mac.xml.i> <leafNode name="min-links"> <properties> <help>Minimum number of member interfaces required up before enabling bond</help> @@ -182,7 +182,7 @@ </leafNode> </children> </node> - #include <include/interface/interface-mtu-68-16000.xml.i> + #include <include/interface/mtu-68-16000.xml.i> <leafNode name="primary"> <properties> <help>Primary device interface</help> @@ -193,7 +193,7 @@ </leafNode> #include <include/interface/vif-s.xml.i> #include <include/interface/vif.xml.i> - #include <include/interface/interface-xdp.xml.i> + #include <include/interface/xdp.xml.i> </children> </tagNode> </children> diff --git a/interface-definitions/interfaces-bridge.xml.in b/interface-definitions/interfaces-bridge.xml.in index 1af002142..ddfc5ade4 100644 --- a/interface-definitions/interfaces-bridge.xml.in +++ b/interface-definitions/interfaces-bridge.xml.in @@ -34,13 +34,13 @@ </properties> <defaultValue>300</defaultValue> </leafNode> - #include <include/interface/interface-description.xml.i> + #include <include/interface/description.xml.i> #include <include/interface/dhcp-options.xml.i> #include <include/interface/dhcpv6-options.xml.i> - #include <include/interface/interface-disable-link-detect.xml.i> - #include <include/interface/interface-disable.xml.i> - #include <include/interface/interface-vrf.xml.i> - #include <include/interface/interface-mtu-68-16000.xml.i> + #include <include/interface/disable-link-detect.xml.i> + #include <include/interface/disable.xml.i> + #include <include/interface/vrf.xml.i> + #include <include/interface/mtu-68-16000.xml.i> <leafNode name="forwarding-delay"> <properties> <help>Forwarding delay</help> @@ -82,10 +82,10 @@ </leafNode> </children> </node> - #include <include/interface/interface-ipv4-options.xml.i> - #include <include/interface/interface-ipv6-options.xml.i> - #include <include/interface/interface-mac.xml.i> - #include <include/interface/interface-mirror.xml.i> + #include <include/interface/ipv4-options.xml.i> + #include <include/interface/ipv6-options.xml.i> + #include <include/interface/mac.xml.i> + #include <include/interface/mirror.xml.i> <leafNode name="enable-vlan"> <properties> <help>Enable VLAN aware bridge</help> diff --git a/interface-definitions/interfaces-dummy.xml.in b/interface-definitions/interfaces-dummy.xml.in index 84c6903c7..2bc88c1a7 100644 --- a/interface-definitions/interfaces-dummy.xml.in +++ b/interface-definitions/interfaces-dummy.xml.in @@ -17,17 +17,17 @@ </properties> <children> #include <include/interface/address-ipv4-ipv6.xml.i> - #include <include/interface/interface-description.xml.i> - #include <include/interface/interface-disable.xml.i> + #include <include/interface/description.xml.i> + #include <include/interface/disable.xml.i> <node name="ip"> <properties> <help>IPv4 routing parameters</help> </properties> <children> - #include <include/interface/interface-source-validation.xml.i> + #include <include/interface/source-validation.xml.i> </children> </node> - #include <include/interface/interface-vrf.xml.i> + #include <include/interface/vrf.xml.i> </children> </tagNode> </children> diff --git a/interface-definitions/interfaces-ethernet.xml.in b/interface-definitions/interfaces-ethernet.xml.in index cb451f5be..ca076e3fa 100644 --- a/interface-definitions/interfaces-ethernet.xml.in +++ b/interface-definitions/interfaces-ethernet.xml.in @@ -20,7 +20,7 @@ </properties> <children> #include <include/interface/address-ipv4-ipv6-dhcp.xml.i> - #include <include/interface/interface-description.xml.i> + #include <include/interface/description.xml.i> #include <include/interface/dhcp-options.xml.i> #include <include/interface/dhcpv6-options.xml.i> <leafNode name="disable-flow-control"> @@ -29,8 +29,8 @@ <valueless/> </properties> </leafNode> - #include <include/interface/interface-disable-link-detect.xml.i> - #include <include/interface/interface-disable.xml.i> + #include <include/interface/disable-link-detect.xml.i> + #include <include/interface/disable.xml.i> <leafNode name="duplex"> <properties> <help>Duplex mode</help> @@ -56,13 +56,13 @@ </properties> <defaultValue>auto</defaultValue> </leafNode> - #include <include/interface/interface-eapol.xml.i> - #include <include/interface/interface-hw-id.xml.i> - #include <include/interface/interface-ipv4-options.xml.i> - #include <include/interface/interface-ipv6-options.xml.i> - #include <include/interface/interface-mac.xml.i> - #include <include/interface/interface-mtu-68-16000.xml.i> - #include <include/interface/interface-mirror.xml.i> + #include <include/interface/eapol.xml.i> + #include <include/interface/hw-id.xml.i> + #include <include/interface/ipv4-options.xml.i> + #include <include/interface/ipv6-options.xml.i> + #include <include/interface/mac.xml.i> + #include <include/interface/mtu-68-16000.xml.i> + #include <include/interface/mirror.xml.i> <node name="offload"> <properties> <help>Configurable offload options</help> @@ -202,8 +202,8 @@ </node> #include <include/interface/vif-s.xml.i> #include <include/interface/vif.xml.i> - #include <include/interface/interface-vrf.xml.i> - #include <include/interface/interface-xdp.xml.i> + #include <include/interface/vrf.xml.i> + #include <include/interface/xdp.xml.i> </children> </tagNode> </children> diff --git a/interface-definitions/interfaces-geneve.xml.in b/interface-definitions/interfaces-geneve.xml.in index bdcbc3f5e..2ca7dd9f6 100644 --- a/interface-definitions/interfaces-geneve.xml.in +++ b/interface-definitions/interfaces-geneve.xml.in @@ -17,12 +17,12 @@ </properties> <children> #include <include/interface/address-ipv4-ipv6.xml.i> - #include <include/interface/interface-description.xml.i> - #include <include/interface/interface-disable.xml.i> - #include <include/interface/interface-ipv4-options.xml.i> - #include <include/interface/interface-ipv6-options.xml.i> - #include <include/interface/interface-mac.xml.i> - #include <include/interface/interface-mtu-1450-16000.xml.i> + #include <include/interface/description.xml.i> + #include <include/interface/disable.xml.i> + #include <include/interface/ipv4-options.xml.i> + #include <include/interface/ipv6-options.xml.i> + #include <include/interface/mac.xml.i> + #include <include/interface/mtu-1450-16000.xml.i> <node name="parameters"> <properties> <help>GENEVE tunnel parameters</help> @@ -33,9 +33,9 @@ <help>IPv4 specific tunnel parameters</help> </properties> <children> - #include <include/interface/interface-parameters-dont-fragment.xml.i> - #include <include/interface/interface-parameters-tos.xml.i> - #include <include/interface/interface-parameters-ttl.xml.i> + #include <include/interface/parameters-dont-fragment.xml.i> + #include <include/interface/parameters-tos.xml.i> + #include <include/interface/parameters-ttl.xml.i> </children> </node> <node name="ipv6"> @@ -43,7 +43,7 @@ <help>IPv6 specific tunnel parameters</help> </properties> <children> - #include <include/interface/interface-parameters-flowlabel.xml.i> + #include <include/interface/parameters-flowlabel.xml.i> </children> </node> </children> diff --git a/interface-definitions/interfaces-l2tpv3.xml.in b/interface-definitions/interfaces-l2tpv3.xml.in index 8835a6b1d..9edc98ef6 100644 --- a/interface-definitions/interfaces-l2tpv3.xml.in +++ b/interface-definitions/interfaces-l2tpv3.xml.in @@ -17,7 +17,7 @@ </properties> <children> #include <include/interface/address-ipv4-ipv6.xml.i> - #include <include/interface/interface-description.xml.i> + #include <include/interface/description.xml.i> <leafNode name="destination-port"> <properties> <help>UDP destination port for L2TPv3 tunnel (default: 5000)</help> @@ -31,7 +31,7 @@ </properties> <defaultValue>5000</defaultValue> </leafNode> - #include <include/interface/interface-disable.xml.i> + #include <include/interface/disable.xml.i> <leafNode name="encapsulation"> <properties> <help>Encapsulation type (default: UDP)</help> @@ -53,10 +53,10 @@ </properties> <defaultValue>udp</defaultValue> </leafNode> - #include <include/interface/interface-ipv4-options.xml.i> - #include <include/interface/interface-ipv6-options.xml.i> + #include <include/interface/ipv4-options.xml.i> + #include <include/interface/ipv6-options.xml.i> #include <include/source-address-ipv4-ipv6.xml.i> - #include <include/interface/interface-mtu-68-16000.xml.i> + #include <include/interface/mtu-68-16000.xml.i> <leafNode name="mtu"> <defaultValue>1488</defaultValue> </leafNode> @@ -84,7 +84,7 @@ </constraint> </properties> </leafNode> - #include <include/interface/interface-mtu-68-16000.xml.i> + #include <include/interface/mtu-68-16000.xml.i> #include <include/interface/tunnel-remote.xml.i> <leafNode name="session-id"> <properties> @@ -123,7 +123,7 @@ </constraint> </properties> </leafNode> - #include <include/interface/interface-vrf.xml.i> + #include <include/interface/vrf.xml.i> </children> </tagNode> </children> diff --git a/interface-definitions/interfaces-loopback.xml.in b/interface-definitions/interfaces-loopback.xml.in index 5d0ca5b0a..7be15ab89 100644 --- a/interface-definitions/interfaces-loopback.xml.in +++ b/interface-definitions/interfaces-loopback.xml.in @@ -17,13 +17,13 @@ </properties> <children> #include <include/interface/address-ipv4-ipv6.xml.i> - #include <include/interface/interface-description.xml.i> + #include <include/interface/description.xml.i> <node name="ip"> <properties> <help>IPv4 routing parameters</help> </properties> <children> - #include <include/interface/interface-source-validation.xml.i> + #include <include/interface/source-validation.xml.i> </children> </node> </children> diff --git a/interface-definitions/interfaces-macsec.xml.in b/interface-definitions/interfaces-macsec.xml.in index fce88b21c..e88cb4794 100644 --- a/interface-definitions/interfaces-macsec.xml.in +++ b/interface-definitions/interfaces-macsec.xml.in @@ -17,8 +17,8 @@ </properties> <children> #include <include/interface/address-ipv4-ipv6.xml.i> - #include <include/interface/interface-ipv4-options.xml.i> - #include <include/interface/interface-ipv6-options.xml.i> + #include <include/interface/ipv4-options.xml.i> + #include <include/interface/ipv6-options.xml.i> <node name="security"> <properties> <help>Security/Encryption Settings</help> @@ -111,14 +111,14 @@ </leafNode> </children> </node> - #include <include/interface/interface-description.xml.i> - #include <include/interface/interface-disable.xml.i> - #include <include/interface/interface-mtu-68-16000.xml.i> + #include <include/interface/description.xml.i> + #include <include/interface/disable.xml.i> + #include <include/interface/mtu-68-16000.xml.i> <leafNode name="mtu"> <defaultValue>1460</defaultValue> </leafNode> #include <include/source-interface-ethernet.xml.i> - #include <include/interface/interface-vrf.xml.i> + #include <include/interface/vrf.xml.i> </children> </tagNode> </children> diff --git a/interface-definitions/interfaces-openvpn.xml.in b/interface-definitions/interfaces-openvpn.xml.in index 7ff08ac86..01e6bf2fb 100644 --- a/interface-definitions/interfaces-openvpn.xml.in +++ b/interface-definitions/interfaces-openvpn.xml.in @@ -33,7 +33,7 @@ </leafNode> </children> </node> - #include <include/interface/interface-description.xml.i> + #include <include/interface/description.xml.i> <leafNode name="device-type"> <properties> <help>OpenVPN interface device-type (default: tun)</help> @@ -54,7 +54,7 @@ </properties> <defaultValue>tun</defaultValue> </leafNode> - #include <include/interface/interface-disable.xml.i> + #include <include/interface/disable.xml.i> <node name="encryption"> <properties> <help>Data Encryption settings</help> @@ -165,7 +165,7 @@ </leafNode> </children> </node> - #include <include/interface/interface-ipv6-options.xml.i> + #include <include/interface/ipv6-options.xml.i> <leafNode name="hash"> <properties> <help>Hashing Algorithm</help> @@ -571,7 +571,7 @@ <multi/> </properties> </leafNode> - <leafNode name="push-route"> + <tagNode name="push-route"> <properties> <help>Route to be pushed to all clients</help> <valueHelp> @@ -585,9 +585,23 @@ <constraint> <validator name="ip-prefix"/> </constraint> - <multi/> </properties> - </leafNode> + <children> + <leafNode name="metric"> + <properties> + <help>Set metric for this route</help> + <valueHelp> + <format>0-4294967295</format> + <description>Metric for this route</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 0-4294967295"/> + </constraint> + </properties> + <defaultValue>0</defaultValue> + </leafNode> + </children> + </tagNode> <leafNode name="reject-unconfigured-clients"> <properties> <help>Reject connections from clients that are not explicitly configured</help> @@ -726,7 +740,7 @@ <valueless/> </properties> </leafNode> - #include <include/interface/interface-vrf.xml.i> + #include <include/interface/vrf.xml.i> </children> </tagNode> </children> diff --git a/interface-definitions/interfaces-pppoe.xml.in b/interface-definitions/interfaces-pppoe.xml.in index 96479e057..57bb01258 100644 --- a/interface-definitions/interfaces-pppoe.xml.in +++ b/interface-definitions/interfaces-pppoe.xml.in @@ -5,7 +5,7 @@ <tagNode name="pppoe" owner="${vyos_conf_scripts_dir}/interfaces-pppoe.py"> <properties> <help>Point-to-Point Protocol over Ethernet (PPPoE)</help> - <priority>321</priority> + <priority>322</priority> <constraint> <regex>^pppoe[0-9]+$</regex> </constraint> @@ -16,17 +16,9 @@ </valueHelp> </properties> <children> - <leafNode name="access-concentrator"> - <properties> - <help>Access concentrator name (only connect to this concentrator)</help> - <constraint> - <regex>[a-zA-Z0-9]+$</regex> - </constraint> - <constraintErrorMessage>Access concentrator name must be composed of uppper and lower case letters or numbers only</constraintErrorMessage> - </properties> - </leafNode> + #include <include/pppoe-access-concentrator.xml.i> #include <include/interface/authentication.xml.i> - #include <include/interface/interface-dial-on-demand.xml.i> + #include <include/interface/dial-on-demand.xml.i> <leafNode name="default-route"> <properties> <help>Default route insertion behaviour (default: auto)</help> @@ -53,16 +45,20 @@ <defaultValue>auto</defaultValue> </leafNode> #include <include/interface/dhcpv6-options.xml.i> - #include <include/interface/interface-description.xml.i> - #include <include/interface/interface-disable.xml.i> - #include <include/interface/interface-vrf.xml.i> + #include <include/interface/description.xml.i> + #include <include/interface/disable.xml.i> + #include <include/interface/vrf.xml.i> <leafNode name="idle-timeout"> <properties> <help>Delay before disconnecting idle session (in seconds)</help> <valueHelp> - <format>n</format> + <format>u32:0-86400</format> <description>Idle timeout in seconds</description> </valueHelp> + <constraint> + <validator name="numeric" argument="--range 0-86400"/> + </constraint> + <constraintErrorMessage>Timeout must be in range 0 to 86400</constraintErrorMessage> </properties> </leafNode> <node name="ip"> @@ -70,7 +66,9 @@ <help>IPv4 routing parameters</help> </properties> <children> - #include <include/interface/interface-source-validation.xml.i> + #include <include/interface/adjust-mss.xml.i> + #include <include/interface/disable-forwarding.xml.i> + #include <include/interface/source-validation.xml.i> </children> </node> <node name="ipv6"> @@ -86,16 +84,11 @@ #include <include/interface/ipv6-address-autoconf.xml.i> </children> </node> + #include <include/interface/adjust-mss.xml.i> + #include <include/interface/disable-forwarding.xml.i> </children> </node> - <leafNode name="source-interface"> - <properties> - <help>Physical Interface used for this PPPoE session</help> - <completionHelp> - <script>${vyos_completion_dir}/list_interfaces.py --broadcast</script> - </completionHelp> - </properties> - </leafNode> + #include <include/source-interface.xml.i> <leafNode name="local-address"> <properties> <help>IPv4 address of local end of the PPPoE link</help> @@ -108,7 +101,7 @@ </constraint> </properties> </leafNode> - #include <include/interface/interface-mtu-68-1500.xml.i> + #include <include/interface/mtu-68-1500.xml.i> <leafNode name="mtu"> <defaultValue>1492</defaultValue> </leafNode> @@ -136,7 +129,7 @@ <constraint> <regex>[a-zA-Z0-9]+$</regex> </constraint> - <constraintErrorMessage>Service name must be composed of uppper and lower case letters or numbers only</constraintErrorMessage> + <constraintErrorMessage>Service name must be alphanumeric only</constraintErrorMessage> </properties> </leafNode> </children> diff --git a/interface-definitions/interfaces-pseudo-ethernet.xml.in b/interface-definitions/interfaces-pseudo-ethernet.xml.in index 136841290..366892032 100644 --- a/interface-definitions/interfaces-pseudo-ethernet.xml.in +++ b/interface-definitions/interfaces-pseudo-ethernet.xml.in @@ -17,16 +17,16 @@ </properties> <children> #include <include/interface/address-ipv4-ipv6-dhcp.xml.i> - #include <include/interface/interface-description.xml.i> + #include <include/interface/description.xml.i> #include <include/interface/dhcp-options.xml.i> #include <include/interface/dhcpv6-options.xml.i> - #include <include/interface/interface-disable-link-detect.xml.i> - #include <include/interface/interface-disable.xml.i> - #include <include/interface/interface-vrf.xml.i> - #include <include/interface/interface-ipv4-options.xml.i> - #include <include/interface/interface-ipv6-options.xml.i> + #include <include/interface/disable-link-detect.xml.i> + #include <include/interface/disable.xml.i> + #include <include/interface/vrf.xml.i> + #include <include/interface/ipv4-options.xml.i> + #include <include/interface/ipv6-options.xml.i> #include <include/source-interface-ethernet.xml.i> - #include <include/interface/interface-mac.xml.i> + #include <include/interface/mac.xml.i> <leafNode name="mode"> <properties> <help>Receive mode (default: private)</help> @@ -56,7 +56,7 @@ </properties> <defaultValue>private</defaultValue> </leafNode> - #include <include/interface/interface-mtu-68-16000.xml.i> + #include <include/interface/mtu-68-16000.xml.i> #include <include/interface/vif-s.xml.i> #include <include/interface/vif.xml.i> </children> diff --git a/interface-definitions/interfaces-tunnel.xml.in b/interface-definitions/interfaces-tunnel.xml.in index b994bdafc..c059ef624 100644 --- a/interface-definitions/interfaces-tunnel.xml.in +++ b/interface-definitions/interfaces-tunnel.xml.in @@ -16,17 +16,17 @@ </valueHelp> </properties> <children> - #include <include/interface/interface-description.xml.i> + #include <include/interface/description.xml.i> #include <include/interface/address-ipv4-ipv6.xml.i> - #include <include/interface/interface-disable.xml.i> - #include <include/interface/interface-disable-link-detect.xml.i> - #include <include/interface/interface-vrf.xml.i> - #include <include/interface/interface-mtu-64-8024.xml.i> + #include <include/interface/disable.xml.i> + #include <include/interface/disable-link-detect.xml.i> + #include <include/interface/vrf.xml.i> + #include <include/interface/mtu-64-8024.xml.i> <leafNode name="mtu"> <defaultValue>1476</defaultValue> </leafNode> - #include <include/interface/interface-ipv4-options.xml.i> - #include <include/interface/interface-ipv6-options.xml.i> + #include <include/interface/ipv4-options.xml.i> + #include <include/interface/ipv6-options.xml.i> #include <include/source-address-ipv4-ipv6.xml.i> #include <include/interface/tunnel-remote.xml.i> #include <include/source-interface.xml.i> @@ -216,9 +216,9 @@ <valueless/> </properties> </leafNode> - #include <include/interface/interface-parameters-key.xml.i> - #include <include/interface/interface-parameters-tos.xml.i> - #include <include/interface/interface-parameters-ttl.xml.i> + #include <include/interface/parameters-key.xml.i> + #include <include/interface/parameters-tos.xml.i> + #include <include/interface/parameters-ttl.xml.i> <leafNode name="ttl"> <defaultValue>64</defaultValue> </leafNode> @@ -251,7 +251,7 @@ </properties> <defaultValue>4</defaultValue> </leafNode> - #include <include/interface/interface-parameters-flowlabel.xml.i> + #include <include/interface/parameters-flowlabel.xml.i> <leafNode name="hoplimit"> <properties> <help>Hoplimit</help> diff --git a/interface-definitions/interfaces-vti.xml.in b/interface-definitions/interfaces-vti.xml.in index 10e1feb6b..b12434ae7 100644 --- a/interface-definitions/interfaces-vti.xml.in +++ b/interface-definitions/interfaces-vti.xml.in @@ -29,10 +29,12 @@ <multi/> </properties> </leafNode> - #include <include/interface/interface-description.xml.i> - #include <include/interface/interface-disable.xml.i> - #include <include/interface/interface-mtu-68-16000.xml.i> - #include <include/interface/interface-vrf.xml.i> + #include <include/interface/description.xml.i> + #include <include/interface/disable.xml.i> + #include <include/interface/ipv4-options.xml.i> + #include <include/interface/ipv6-options.xml.i> + #include <include/interface/mtu-68-16000.xml.i> + #include <include/interface/vrf.xml.i> </children> </tagNode> </children> diff --git a/interface-definitions/interfaces-vxlan.xml.in b/interface-definitions/interfaces-vxlan.xml.in index 56d01dfb6..43b73a2e9 100644 --- a/interface-definitions/interfaces-vxlan.xml.in +++ b/interface-definitions/interfaces-vxlan.xml.in @@ -17,8 +17,8 @@ </properties> <children> #include <include/interface/address-ipv4-ipv6.xml.i> - #include <include/interface/interface-description.xml.i> - #include <include/interface/interface-disable.xml.i> + #include <include/interface/description.xml.i> + #include <include/interface/disable.xml.i> <leafNode name="group"> <properties> <help>Multicast group address for VXLAN interface</help> @@ -35,10 +35,10 @@ </constraint> </properties> </leafNode> - #include <include/interface/interface-ipv4-options.xml.i> - #include <include/interface/interface-ipv6-options.xml.i> - #include <include/interface/interface-mac.xml.i> - #include <include/interface/interface-mtu-1200-16000.xml.i> + #include <include/interface/ipv4-options.xml.i> + #include <include/interface/ipv6-options.xml.i> + #include <include/interface/mac.xml.i> + #include <include/interface/mtu-1200-16000.xml.i> <leafNode name="mtu"> <defaultValue>1450</defaultValue> </leafNode> @@ -52,9 +52,9 @@ <help>IPv4 specific tunnel parameters</help> </properties> <children> - #include <include/interface/interface-parameters-dont-fragment.xml.i> - #include <include/interface/interface-parameters-tos.xml.i> - #include <include/interface/interface-parameters-ttl.xml.i> + #include <include/interface/parameters-dont-fragment.xml.i> + #include <include/interface/parameters-tos.xml.i> + #include <include/interface/parameters-ttl.xml.i> <leafNode name="ttl"> <defaultValue>16</defaultValue> </leafNode> @@ -65,7 +65,7 @@ <help>IPv6 specific tunnel parameters</help> </properties> <children> - #include <include/interface/interface-parameters-flowlabel.xml.i> + #include <include/interface/parameters-flowlabel.xml.i> </children> </node> <leafNode name="nolearning"> @@ -76,23 +76,14 @@ </leafNode> </children> </node> + #include <include/port-number.xml.i> <leafNode name="port"> - <properties> - <help>Destination port of VXLAN tunnel (default: 8472)</help> - <valueHelp> - <format>u32:1-65535</format> - <description>Numeric IP port</description> - </valueHelp> - <constraint> - <validator name="numeric" argument="--range 1-65535"/> - </constraint> - </properties> <defaultValue>8472</defaultValue> </leafNode> #include <include/source-address-ipv4-ipv6.xml.i> #include <include/source-interface.xml.i> #include <include/interface/tunnel-remote.xml.i> - #include <include/interface/interface-vrf.xml.i> + #include <include/interface/vrf.xml.i> #include <include/vni.xml.i> </children> </tagNode> diff --git a/interface-definitions/interfaces-wireguard.xml.in b/interface-definitions/interfaces-wireguard.xml.in index 773bde09c..ecb4cf331 100644 --- a/interface-definitions/interfaces-wireguard.xml.in +++ b/interface-definitions/interfaces-wireguard.xml.in @@ -17,16 +17,16 @@ </properties> <children> #include <include/interface/address-ipv4-ipv6.xml.i> - #include <include/interface/interface-description.xml.i> - #include <include/interface/interface-disable.xml.i> - #include <include/interface/interface-vrf.xml.i> + #include <include/interface/description.xml.i> + #include <include/interface/disable.xml.i> + #include <include/interface/vrf.xml.i> #include <include/port-number.xml.i> - #include <include/interface/interface-mtu-68-16000.xml.i> + #include <include/interface/mtu-68-16000.xml.i> <leafNode name="mtu"> <defaultValue>1420</defaultValue> </leafNode> - #include <include/interface/interface-ipv4-options.xml.i> - #include <include/interface/interface-ipv6-options.xml.i> + #include <include/interface/ipv4-options.xml.i> + #include <include/interface/ipv6-options.xml.i> <leafNode name="fwmark"> <properties> <help>A 32-bit fwmark value set on all outgoing packets</help> @@ -102,18 +102,7 @@ </constraint> </properties> </leafNode> - <leafNode name="port"> - <properties> - <help>Port number used for tunnel endpoint</help> - <valueHelp> - <format>u32:1-65535</format> - <description>Numeric IP port</description> - </valueHelp> - <constraint> - <validator name="numeric" argument="--range 1-65535"/> - </constraint> - </properties> - </leafNode> + #include <include/port-number.xml.i> <leafNode name="persistent-keepalive"> <properties> <help>Interval to send keepalive messages</help> diff --git a/interface-definitions/interfaces-wireless.xml.in b/interface-definitions/interfaces-wireless.xml.in index aaeb285f1..c96d9b78d 100644 --- a/interface-definitions/interfaces-wireless.xml.in +++ b/interface-definitions/interfaces-wireless.xml.in @@ -464,7 +464,7 @@ <constraintErrorMessage>Invalid ISO/IEC 3166-1 Country Code</constraintErrorMessage> </properties> </leafNode> - #include <include/interface/interface-description.xml.i> + #include <include/interface/description.xml.i> #include <include/interface/dhcp-options.xml.i> #include <include/interface/dhcpv6-options.xml.i> <leafNode name="disable-broadcast-ssid"> @@ -473,25 +473,25 @@ <valueless/> </properties> </leafNode> - #include <include/interface/interface-disable-link-detect.xml.i> - #include <include/interface/interface-disable.xml.i> - #include <include/interface/interface-vrf.xml.i> + #include <include/interface/disable-link-detect.xml.i> + #include <include/interface/disable.xml.i> + #include <include/interface/vrf.xml.i> <leafNode name="expunge-failing-stations"> <properties> <help>Disassociate stations based on excessive transmission failures</help> <valueless/> </properties> </leafNode> - #include <include/interface/interface-ipv4-options.xml.i> - #include <include/interface/interface-ipv6-options.xml.i> - #include <include/interface/interface-hw-id.xml.i> + #include <include/interface/ipv4-options.xml.i> + #include <include/interface/ipv6-options.xml.i> + #include <include/interface/hw-id.xml.i> <leafNode name="isolate-stations"> <properties> <help>Isolate stations on the AP so they cannot see each other</help> <valueless/> </properties> </leafNode> - #include <include/interface/interface-mac.xml.i> + #include <include/interface/mac.xml.i> <leafNode name="max-stations"> <properties> <help>Maximum number of wireless radio stations. Excess stations will be rejected upon authentication request.</help> diff --git a/interface-definitions/interfaces-wwan.xml.in b/interface-definitions/interfaces-wwan.xml.in index ea3184a11..6b6fa1a66 100644 --- a/interface-definitions/interfaces-wwan.xml.in +++ b/interface-definitions/interfaces-wwan.xml.in @@ -28,17 +28,17 @@ #include <include/interface/dhcp-options.xml.i> #include <include/interface/dhcpv6-options.xml.i> #include <include/interface/authentication.xml.i> - #include <include/interface/interface-description.xml.i> - #include <include/interface/interface-disable.xml.i> - #include <include/interface/interface-vrf.xml.i> - #include <include/interface/interface-disable-link-detect.xml.i> - #include <include/interface/interface-mtu-68-1500.xml.i> + #include <include/interface/description.xml.i> + #include <include/interface/disable.xml.i> + #include <include/interface/vrf.xml.i> + #include <include/interface/disable-link-detect.xml.i> + #include <include/interface/mtu-68-1500.xml.i> <leafNode name="mtu"> <defaultValue>1430</defaultValue> </leafNode> - #include <include/interface/interface-ipv4-options.xml.i> - #include <include/interface/interface-ipv6-options.xml.i> - #include <include/interface/interface-dial-on-demand.xml.i> + #include <include/interface/ipv4-options.xml.i> + #include <include/interface/ipv6-options.xml.i> + #include <include/interface/dial-on-demand.xml.i> </children> </tagNode> </children> diff --git a/interface-definitions/ntp.xml.in b/interface-definitions/ntp.xml.in index 2bfac900b..a518a9def 100644 --- a/interface-definitions/ntp.xml.in +++ b/interface-definitions/ntp.xml.in @@ -82,7 +82,7 @@ </children> </node> #include <include/listen-address.xml.i> - #include <include/interface/interface-vrf.xml.i> + #include <include/interface/vrf.xml.i> </children> </node> </children> diff --git a/interface-definitions/policy-local-route.xml.in b/interface-definitions/policy-local-route.xml.in index 3769c3748..86445b65d 100644 --- a/interface-definitions/policy-local-route.xml.in +++ b/interface-definitions/policy-local-route.xml.in @@ -40,6 +40,18 @@ </leafNode> </children> </node> + <leafNode name="fwmark"> + <properties> + <help>Match fwmark value</help> + <valueHelp> + <format>u32:1-2147483647</format> + <description>Address to match against</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 1-2147483647"/> + </constraint> + </properties> + </leafNode> <leafNode name="source"> <properties> <help>Source address or prefix</help> diff --git a/interface-definitions/policy.xml.in b/interface-definitions/policy.xml.in index fb62d2f89..cf65daf00 100644 --- a/interface-definitions/policy.xml.in +++ b/interface-definitions/policy.xml.in @@ -139,7 +139,7 @@ </tagNode> <tagNode name="as-path-list"> <properties> - <help>Border Gateway Protocol (BGP) autonomous system path filter</help> + <help>Add a BGP autonomous system path filter</help> <valueHelp> <format>txt</format> <description>AS path list name</description> @@ -176,10 +176,10 @@ </tagNode> <tagNode name="community-list"> <properties> - <help>Border Gateway Protocol (BGP) autonomous system path filter</help> + <help>Add a BGP community list entry</help> <valueHelp> <format>txt</format> - <description>Border Gateway Protocol (BGP) community-list filter</description> + <description>BGP community-list name</description> </valueHelp> </properties> <children> @@ -236,11 +236,15 @@ </tagNode> <tagNode name="extcommunity-list"> <properties> - <help>Border Gateway Protocol (BGP) extended community-list filter</help> + <help>Add a BGP extended community list entry</help> <valueHelp> <format>txt</format> - <description>Border Gateway Protocol (BGP) extended community-list filter</description> + <description>BGP extended community-list name</description> </valueHelp> + <constraint> + <regex>^[-_a-zA-Z0-9]+$</regex> + </constraint> + <constraintErrorMessage>Should be an alphanumeric name</constraintErrorMessage> </properties> <children> #include <include/generic-description.xml.i> @@ -281,11 +285,15 @@ </tagNode> <tagNode name="large-community-list"> <properties> - <help>Border Gateway Protocol (BGP) large-community-list filter</help> + <help>Add a BGP large community list entry</help> <valueHelp> <format>txt</format> - <description>Border Gateway Protocol (BGP) large-community-list filter</description> + <description>BGP large-community-list name</description> </valueHelp> + <constraint> + <regex>^[-_a-zA-Z0-9]+$</regex> + </constraint> + <constraintErrorMessage>Should be an alphanumeric name</constraintErrorMessage> </properties> <children> #include <include/generic-description.xml.i> @@ -307,9 +315,17 @@ <properties> <help>Regular expression to match against a large community list</help> <valueHelp> - <format><aa:nn:nn></format> - <description>Large Community value</description> + <format>ASN:NN:NN</format> + <description>BGP large-community-list filter</description> </valueHelp> + <valueHelp> + <format>IP:NN:NN</format> + <description>BGP large-community-list filter (IPv4 address format)</description> + </valueHelp> + <constraint> + <validator name="bgp-large-community-list"/> + </constraint> + <constraintErrorMessage>Malformed large-community-list</constraintErrorMessage> </properties> </leafNode> </children> @@ -808,7 +824,7 @@ </leafNode> <leafNode name="origin"> <properties> - <help>Border Gateway Protocol (BGP) origin code to match</help> + <help>BGP origin code to match</help> <completionHelp> <list>egp igp incomplete</list> </completionHelp> @@ -910,7 +926,7 @@ <children> <node name="aggregator"> <properties> - <help>Border Gateway Protocol (BGP) aggregator attribute</help> + <help>BGP aggregator attribute</help> </properties> <children> <leafNode name="as"> @@ -959,13 +975,13 @@ </leafNode> <leafNode name="atomic-aggregate"> <properties> - <help>Border Gateway Protocol (BGP) atomic aggregate attribute</help> + <help>BGP atomic aggregate attribute</help> <valueless/> </properties> </leafNode> <node name="comm-list"> <properties> - <help>Border Gateway Protocol (BGP) communities matching a community-list</help> + <help>BGP communities matching a community-list</help> </properties> <children> <leafNode name="comm-list"> @@ -1162,9 +1178,21 @@ </completionHelp> </properties> </leafNode> + <leafNode name="large-comm-list-delete"> + <properties> + <help>Delete BGP communities matching the large community-list</help> + <completionHelp> + <path>policy large-community-list</path> + </completionHelp> + <valueHelp> + <format>txt</format> + <description>BGP large community-list</description> + </valueHelp> + </properties> + </leafNode> <leafNode name="local-preference"> <properties> - <help>Border Gateway Protocol (BGP) local preference attribute</help> + <help>BGP local preference attribute</help> <valueHelp> <format>u32:0-4294967295</format> <description>Local preference value</description> @@ -1234,7 +1262,7 @@ </leafNode> <leafNode name="originator-id"> <properties> - <help>Border Gateway Protocol (BGP) originator ID attribute</help> + <help>BGP originator ID attribute</help> <valueHelp> <format>ipv4</format> <description>Orignator IP address</description> @@ -1287,7 +1315,7 @@ </leafNode> <leafNode name="weight"> <properties> - <help>Border Gateway Protocol (BGP) weight attribute</help> + <help>BGP weight attribute</help> <valueHelp> <format>u32:0-4294967295</format> <description>BGP weight</description> diff --git a/interface-definitions/service_console-server.xml.in b/interface-definitions/service_console-server.xml.in index 78eb2d0ba..28aa7ea71 100644 --- a/interface-definitions/service_console-server.xml.in +++ b/interface-definitions/service_console-server.xml.in @@ -27,7 +27,7 @@ </constraint> </properties> <children> - #include <include/interface/interface-description.xml.i> + #include <include/interface/description.xml.i> <leafNode name="speed"> <properties> <help>Serial port baud rate</help> diff --git a/interface-definitions/service_pppoe-server.xml.in b/interface-definitions/service_pppoe-server.xml.in index 7b96b5692..79042e0f3 100644 --- a/interface-definitions/service_pppoe-server.xml.in +++ b/interface-definitions/service_pppoe-server.xml.in @@ -8,14 +8,8 @@ <priority>900</priority> </properties> <children> + #include <include/pppoe-access-concentrator.xml.i> <leafNode name="access-concentrator"> - <properties> - <help>Access concentrator name</help> - <constraint> - <regex>[a-zA-Z0-9]{1,100}</regex> - </constraint> - <constraintErrorMessage>access-concentrator name limited to alphanumerical characters only (max. 100)</constraintErrorMessage> - </properties> <defaultValue>vyos-ac</defaultValue> </leafNode> <node name="authentication"> @@ -129,7 +123,7 @@ <constraint> <regex>[a-zA-Z0-9\-]{1,100}</regex> </constraint> - <constraintErrorMessage>servicename can contain aplhanumerical characters and dashes only (max. 100)</constraintErrorMessage> + <constraintErrorMessage>Service-name can contain aplhanumerical characters and dashes only (max. 100)</constraintErrorMessage> <multi/> </properties> </leafNode> diff --git a/interface-definitions/service_webproxy.xml.in b/interface-definitions/service_webproxy.xml.in index 7cb0f7ece..64747420b 100644 --- a/interface-definitions/service_webproxy.xml.in +++ b/interface-definitions/service_webproxy.xml.in @@ -83,17 +83,8 @@ <valueless/> </properties> </leafNode> + #include <include/port-number.xml.i> <leafNode name="port"> - <properties> - <help>LDAP server port to use (default: 389)</help> - <valueHelp> - <format>u32:1-65535</format> - <description>Port number to use</description> - </valueHelp> - <constraint> - <validator name="numeric" argument="--range 1-65535"/> - </constraint> - </properties> <defaultValue>389</defaultValue> </leafNode> <leafNode name="server"> @@ -214,7 +205,7 @@ <properties> <help>Cache peer options (default: "no-query default")</help> <valueHelp> - <format>text</format> + <format>txt</format> <description>Cache peer options</description> </valueHelp> </properties> diff --git a/interface-definitions/snmp.xml.in b/interface-definitions/snmp.xml.in index 2654449a1..b0b7768d2 100644 --- a/interface-definitions/snmp.xml.in +++ b/interface-definitions/snmp.xml.in @@ -646,7 +646,7 @@ </tagNode> </children> </node> - #include <include/interface/interface-vrf.xml.i> + #include <include/interface/vrf.xml.i> </children> </node> </children> diff --git a/interface-definitions/ssh.xml.in b/interface-definitions/ssh.xml.in index 54742f1d0..c447f144d 100644 --- a/interface-definitions/ssh.xml.in +++ b/interface-definitions/ssh.xml.in @@ -146,7 +146,7 @@ </constraint> </properties> </leafNode> - #include <include/interface/interface-vrf.xml.i> + #include <include/interface/vrf.xml.i> </children> </node> </children> diff --git a/interface-definitions/system-conntrack.xml.in b/interface-definitions/system-conntrack.xml.in index fa73df3db..daa4177c9 100644 --- a/interface-definitions/system-conntrack.xml.in +++ b/interface-definitions/system-conntrack.xml.in @@ -37,65 +37,51 @@ </leafNode> <node name="modules"> <properties> - <help>Connection tracking modules settings</help> + <help>Connection tracking modules</help> </properties> <children> - <node name="ftp"> + <leafNode name="ftp"> <properties> - <help>FTP connection tracking settings</help> + <help>FTP connection tracking</help> + <valueless/> </properties> - <children> - #include <include/conntrack-module-disable.xml.i> - </children> - </node> - <node name="h323"> + </leafNode> + <leafNode name="h323"> <properties> - <help>H.323 connection tracking settings</help> + <help>H.323 connection tracking</help> + <valueless/> </properties> - <children> - #include <include/conntrack-module-disable.xml.i> - </children> - </node> - <node name="nfs"> + </leafNode> + <leafNode name="nfs"> <properties> - <help>NFS connection tracking settings</help> + <help>NFS connection tracking</help> + <valueless/> </properties> - <children> - #include <include/conntrack-module-disable.xml.i> - </children> - </node> - <node name="pptp"> + </leafNode> + <leafNode name="pptp"> <properties> - <help>PPTP connection tracking settings</help> + <help>PPTP connection tracking</help> + <valueless/> </properties> - <children> - #include <include/conntrack-module-disable.xml.i> - </children> - </node> - <node name="sip"> + </leafNode> + <leafNode name="sip"> <properties> - <help>SIP connection tracking settings</help> + <help>SIP connection tracking</help> + <valueless/> </properties> - <children> - #include <include/conntrack-module-disable.xml.i> - </children> - </node> - <node name="sqlnet"> + </leafNode> + <leafNode name="sqlnet"> <properties> - <help>SQLnet connection tracking settings</help> + <help>SQLnet connection tracking</help> + <valueless/> </properties> - <children> - #include <include/conntrack-module-disable.xml.i> - </children> - </node> - <node name="tftp"> + </leafNode> + <leafNode name="tftp"> <properties> - <help>TFTP connection tracking settings</help> + <help>TFTP connection tracking</help> + <valueless/> </properties> - <children> - #include <include/conntrack-module-disable.xml.i> - </children> - </node> + </leafNode> </children> </node> <leafNode name="table-size"> diff --git a/interface-definitions/system-login.xml.in b/interface-definitions/system-login.xml.in index 86db3f368..fb34b7199 100644 --- a/interface-definitions/system-login.xml.in +++ b/interface-definitions/system-login.xml.in @@ -145,7 +145,7 @@ </leafNode> </children> </tagNode> - #include <include/interface/interface-vrf.xml.i> + #include <include/interface/vrf.xml.i> </children> </node> </children> diff --git a/interface-definitions/system-proxy.xml.in b/interface-definitions/system-proxy.xml.in index 791f41f2f..ade168522 100644 --- a/interface-definitions/system-proxy.xml.in +++ b/interface-definitions/system-proxy.xml.in @@ -15,18 +15,7 @@ </constraint> </properties> </leafNode> - <leafNode name="port"> - <properties> - <help>Proxy port</help> - <valueHelp> - <format>u32:1-65535</format> - <description>Numeric IP port</description> - </valueHelp> - <constraint> - <validator name="numeric" argument="--range 1-65535"/> - </constraint> - </properties> - </leafNode> + #include <include/port-number.xml.i> <leafNode name="username"> <properties> <help>Proxy username</help> diff --git a/interface-definitions/system-syslog.xml.in b/interface-definitions/system-syslog.xml.in index f3dcae2f3..9280a43c8 100644 --- a/interface-definitions/system-syslog.xml.in +++ b/interface-definitions/system-syslog.xml.in @@ -195,19 +195,7 @@ </valueHelp> </properties> <children> - <leafNode name="port"> - <properties> - <help>Destination port</help> - <valueHelp> - <format>u32:1-65535</format> - <description>Destination port</description> - </valueHelp> - <constraint> - <validator name="numeric" argument="--range 1-65535"/> - </constraint> - <constraintErrorMessage>Invalid destination port value</constraintErrorMessage> - </properties> - </leafNode> + #include <include/port-number.xml.i> <tagNode name="facility"> <properties> <help>Facility for logging</help> diff --git a/interface-definitions/tftp-server.xml.in b/interface-definitions/tftp-server.xml.in index e903e8f4e..037c097ca 100644 --- a/interface-definitions/tftp-server.xml.in +++ b/interface-definitions/tftp-server.xml.in @@ -20,17 +20,8 @@ <valueless/> </properties> </leafNode> + #include <include/port-number.xml.i> <leafNode name="port"> - <properties> - <help>Port number used to listen for connections</help> - <valueHelp> - <format>u32:1-65535</format> - <description>Numeric IP port</description> - </valueHelp> - <constraint> - <validator name="numeric" argument="--range 1-65535"/> - </constraint> - </properties> <defaultValue>69</defaultValue> </leafNode> #include <include/listen-address.xml.i> diff --git a/interface-definitions/vpn_ipsec.xml.in b/interface-definitions/vpn_ipsec.xml.in index b28c86ae6..b0dba4bce 100644 --- a/interface-definitions/vpn_ipsec.xml.in +++ b/interface-definitions/vpn_ipsec.xml.in @@ -771,11 +771,19 @@ <help>Pool name used for IP address assignments</help> <completionHelp> <path>vpn ipsec remote-access pool</path> - <list>dhcp</list> + <list>dhcp radius</list> </completionHelp> <valueHelp> <format>txt</format> - <description>Pool name</description> + <description>Name of predefined IP pool</description> + </valueHelp> + <valueHelp> + <format>dhcp</format> + <description>Forward requests for virtual IP addresses to a DHCP server</description> + </valueHelp> + <valueHelp> + <format>radius</format> + <description>Forward requests for virtual IP addresses to a RADIUS server</description> </valueHelp> <multi/> </properties> diff --git a/interface-definitions/vpn_l2tp.xml.in b/interface-definitions/vpn_l2tp.xml.in index cf31af70f..907bcaadb 100644 --- a/interface-definitions/vpn_l2tp.xml.in +++ b/interface-definitions/vpn_l2tp.xml.in @@ -5,6 +5,7 @@ <node name="l2tp" owner="${vyos_conf_scripts_dir}/vpn_l2tp.py"> <properties> <help>L2TP Virtual Private Network (VPN)</help> + <priority>902</priority> </properties> <children> <node name="remote-access"> diff --git a/interface-definitions/vpn_sstp.xml.in b/interface-definitions/vpn_sstp.xml.in index 3576bac90..5cd331d7f 100644 --- a/interface-definitions/vpn_sstp.xml.in +++ b/interface-definitions/vpn_sstp.xml.in @@ -25,7 +25,7 @@ </node> </children> </node> - #include <include/interface/interface-mtu-68-1500.xml.i> + #include <include/interface/mtu-68-1500.xml.i> #include <include/accel-ppp/gateway-address.xml.i> #include <include/accel-ppp/name-server.xml.i> <node name="client-ip-pool"> diff --git a/interface-definitions/vrf.xml.in b/interface-definitions/vrf.xml.in index 9d513945c..2ed50ec5c 100644 --- a/interface-definitions/vrf.xml.in +++ b/interface-definitions/vrf.xml.in @@ -26,8 +26,8 @@ </valueHelp> </properties> <children> - #include <include/interface/interface-description.xml.i> - #include <include/interface/interface-disable.xml.i> + #include <include/interface/description.xml.i> + #include <include/interface/disable.xml.i> <node name="protocols"> <properties> <help>Routing protocol parameters</help> @@ -85,7 +85,20 @@ <constraintErrorMessage>VRF routing table must be in range from 100 to 65535</constraintErrorMessage> </properties> </leafNode> - #include <include/vni.xml.i> + <leafNode name="vni" owner="${vyos_conf_scripts_dir}/vrf_vni.py $VAR(../@)"> + <properties> + <help>Virtual Network Identifier</help> + <!-- priority must be after BGP --> + <priority>822</priority> + <valueHelp> + <format>0-16777214</format> + <description>VXLAN virtual network identifier</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 0-16777214"/> + </constraint> + </properties> + </leafNode> </children> </tagNode> </children> diff --git a/interface-definitions/vrrp.xml.in b/interface-definitions/vrrp.xml.in index bb551296f..7bbe25347 100644 --- a/interface-definitions/vrrp.xml.in +++ b/interface-definitions/vrrp.xml.in @@ -45,7 +45,7 @@ <properties> <help>VRRP password</help> <valueHelp> - <format>text</format> + <format>txt</format> <description>Password string (up to 8 characters)</description> </valueHelp> <constraint> @@ -285,7 +285,7 @@ <multi/> <help>Sync group member</help> <valueHelp> - <format>text</format> + <format>txt</format> <description>VRRP group name</description> </valueHelp> <completionHelp> diff --git a/op-mode-definitions/containers.xml.in b/op-mode-definitions/containers.xml.in index a22549dd9..b2b318786 100644 --- a/op-mode-definitions/containers.xml.in +++ b/op-mode-definitions/containers.xml.in @@ -17,6 +17,19 @@ </node> </children> </node> + <node name="connect"> + <children> + <tagNode name="container"> + <properties> + <help>Attach to a running container</help> + <completionHelp> + <path>container name</path> + </completionHelp> + </properties> + <command>sudo podman exec --interactive --tty "$3" /bin/sh</command> + </tagNode> + </children> + </node> <node name="delete"> <children> <node name="container"> @@ -27,6 +40,9 @@ <tagNode name="image"> <properties> <help>Delete container image</help> + <completionHelp> + <script>sudo podman image ls -q</script> + </completionHelp> </properties> <command>sudo ${vyos_op_scripts_dir}/containers_op.py --remove "${4}"</command> </tagNode> @@ -48,6 +64,15 @@ </properties> <command>sudo ${vyos_op_scripts_dir}/containers_op.py --image</command> </leafNode> + <tagNode name="log"> + <properties> + <help>Show logs from a given container</help> + <completionHelp> + <path>container name</path> + </completionHelp> + </properties> + <command>sudo podman logs --names "$4"</command> + </tagNode> <leafNode name="network"> <properties> <help>Show available container networks</help> @@ -56,6 +81,52 @@ </leafNode> </children> </node> + <node name="log"> + <children> + <tagNode name="container"> + <properties> + <help>Show logs from a given container</help> + <completionHelp> + <path>container name</path> + </completionHelp> + </properties> + <command>sudo podman logs --names "$4"</command> + </tagNode> + </children> + </node> + </children> + </node> + <node name="restart"> + <children> + <tagNode name="container"> + <properties> + <help>Restart a given container</help> + <completionHelp> + <path>container name</path> + </completionHelp> + </properties> + <command>sudo podman restart "$3"</command> + </tagNode> + </children> + </node> + <node name="update"> + <children> + <node name="container"> + <properties> + <help>Update a container image</help> + </properties> + <children> + <tagNode name="image"> + <properties> + <help>Delete container image</help> + <completionHelp> + <path>container name</path> + </completionHelp> + </properties> + <command>sudo ${vyos_op_scripts_dir}/containers_op.py --update "${4}"</command> + </tagNode> + </children> + </node> </children> </node> </interfaceDefinition> diff --git a/op-mode-definitions/dns-forwarding.xml.in b/op-mode-definitions/dns-forwarding.xml.in index 36fe6b5ef..6574f2319 100644 --- a/op-mode-definitions/dns-forwarding.xml.in +++ b/op-mode-definitions/dns-forwarding.xml.in @@ -59,9 +59,6 @@ </children> </node> <node name="reset"> - <properties> - <help>Reset a service</help> - </properties> <children> <node name="dns"> <properties> diff --git a/op-mode-definitions/generate-ipsec-profile.xml.in b/op-mode-definitions/generate-ipsec-profile.xml.in index be9227971..8d1051b94 100644 --- a/op-mode-definitions/generate-ipsec-profile.xml.in +++ b/op-mode-definitions/generate-ipsec-profile.xml.in @@ -100,37 +100,6 @@ </completionHelp> </properties> <command>${vyos_op_scripts_dir}/ikev2_profile_generator.py --os windows --connection "$5" --remote "$7" --name "$9"</command> - <children> - <tagNode name="profile"> - <properties> - <help>Profile name as seen under system profiles</help> - <completionHelp> - <list><name></list> - </completionHelp> - </properties> - <command>${vyos_op_scripts_dir}/ikev2_profile_generator.py --os windows --connection "$5" --remote "$7" --name "$9" --profile "${11}"</command> - </tagNode> - </children> - </tagNode> - <tagNode name="profile"> - <properties> - <help>Profile name as seen under system profiles</help> - <completionHelp> - <list><name></list> - </completionHelp> - </properties> - <command>${vyos_op_scripts_dir}/ikev2_profile_generator.py --os windows --connection "$5" --remote "$7" --profile "$9"</command> - <children> - <tagNode name="name"> - <properties> - <help>Connection name as seen in the VPN application</help> - <completionHelp> - <list><name></list> - </completionHelp> - </properties> - <command>${vyos_op_scripts_dir}/ikev2_profile_generator.py --os windows --connection "$5" --remote "$7" --profile "$9" --name "${11}"</command> - </tagNode> - </children> </tagNode> </children> </tagNode> diff --git a/op-mode-definitions/include/bgp/afi-common.xml.i b/op-mode-definitions/include/bgp/afi-common.xml.i index 7fc59f3b0..4d5f56656 100644 --- a/op-mode-definitions/include/bgp/afi-common.xml.i +++ b/op-mode-definitions/include/bgp/afi-common.xml.i @@ -7,23 +7,33 @@ </completionHelp> </properties> <children> - <leafNode name="exact-match"> - <properties> - <help>Exact match of the communities</help> - </properties> - <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> - </leafNode> + #include <include/bgp/exact-match.xml.i> </children> <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> </tagNode> <tagNode name="large-community"> <properties> - <help>List of large-community numbers</help> + <help>Display routes matching the large-communities</help> <completionHelp> <list>AA:BB:CC</list> </completionHelp> </properties> <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + <children> + #include <include/bgp/exact-match.xml.i> + </children> +</tagNode> +<tagNode name="large-community-list"> + <properties> + <help>Display routes matching the large-community-list</help> + <completionHelp> + <path>policy large-community-list</path> + </completionHelp> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + <children> + #include <include/bgp/exact-match.xml.i> + </children> </tagNode> <leafNode name="statistics"> <properties> 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 f1b699347..a51595b7f 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 @@ -22,12 +22,7 @@ </properties> <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> </leafNode> - <leafNode name="exact-match"> - <properties> - <help>Exact match of the communities</help> - </properties> - <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> - </leafNode> + #include <include/bgp/exact-match.xml.i> <leafNode name="graceful-shutdown"> <properties> <help>Graceful shutdown (well-known community)</help> @@ -105,12 +100,7 @@ </completionHelp> </properties> <children> - <leafNode name="exact-match"> - <properties> - <help>Show BGP routes exactly matching specified community list</help> - </properties> - <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> - </leafNode> + #include <include/bgp/exact-match.xml.i> </children> <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> </tagNode> diff --git a/op-mode-definitions/include/bgp/afi-ipv4-ipv6-vpn.xml.i b/op-mode-definitions/include/bgp/afi-ipv4-ipv6-vpn.xml.i new file mode 100644 index 000000000..ba6edb256 --- /dev/null +++ b/op-mode-definitions/include/bgp/afi-ipv4-ipv6-vpn.xml.i @@ -0,0 +1,23 @@ +<!-- included start from bgp/afi-ipv4-ipv6-vpn.xml.i --> +<tagNode name="vpn"> + <properties> + <help>Network in the BGP routing table to display</help> + <completionHelp> + <list><x.x.x.x> <x.x.x.x/x> <h:h:h:h:h:h:h:h> <h:h:h:h:h:h:h:h/x></list> + </completionHelp> + </properties> + <children> + #include <include/bgp/prefix-bestpath-multipath.xml.i> + </children> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> +</tagNode> +<node name="vpn"> + <properties> + <help>VPN Address Family modifier</help> + </properties> + <children> + #include <include/bgp/afi-common.xml.i> + #include <include/bgp/afi-ipv4-ipv6-common.xml.i> + </children> +</node> +<!-- included end --> diff --git a/op-mode-definitions/include/bgp/exact-match.xml.i b/op-mode-definitions/include/bgp/exact-match.xml.i new file mode 100644 index 000000000..49026db9b --- /dev/null +++ b/op-mode-definitions/include/bgp/exact-match.xml.i @@ -0,0 +1,8 @@ +<!-- included start from bgp/exact-match.xml.i --> +<leafNode name="exact-match"> + <properties> + <help>Exact match of the communities</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 b86b09056..0664b11fc 100644 --- a/op-mode-definitions/include/bgp/show-bgp-common.xml.i +++ b/op-mode-definitions/include/bgp/show-bgp-common.xml.i @@ -20,6 +20,7 @@ <children> #include <include/bgp/afi-common.xml.i> #include <include/bgp/afi-ipv4-ipv6-common.xml.i> + #include <include/bgp/afi-ipv4-ipv6-vpn.xml.i> </children> </node> <tagNode name="ipv6"> @@ -41,6 +42,7 @@ <children> #include <include/bgp/afi-common.xml.i> #include <include/bgp/afi-ipv4-ipv6-common.xml.i> + #include <include/bgp/afi-ipv4-ipv6-vpn.xml.i> </children> </node> <node name="l2vpn"> diff --git a/op-mode-definitions/ipv4-route.xml.in b/op-mode-definitions/ipv4-route.xml.in index aab3df0f1..8f001d5bb 100644 --- a/op-mode-definitions/ipv4-route.xml.in +++ b/op-mode-definitions/ipv4-route.xml.in @@ -20,11 +20,7 @@ </node> </children> </node> - <node name="reset"> - <properties> - <help>Reset a service</help> - </properties> <children> <node name="ip"> <properties> @@ -56,7 +52,6 @@ </tagNode> </children> </node> - <node name="route"> <properties> <help>Reset IP route</help> @@ -68,7 +63,6 @@ </properties> <command>sudo ip route flush cache</command> </leafNode> - <tagNode name="cache"> <properties> <help>Flush the kernel route cache for a given route</help> diff --git a/op-mode-definitions/ipv6-route.xml.in b/op-mode-definitions/ipv6-route.xml.in index 7f188fdb2..5f20444d4 100644 --- a/op-mode-definitions/ipv6-route.xml.in +++ b/op-mode-definitions/ipv6-route.xml.in @@ -28,11 +28,7 @@ </node> </children> </node> - <node name="reset"> - <properties> - <help>Reset a service</help> - </properties> <children> <node name="ipv6"> <properties> @@ -64,7 +60,6 @@ </tagNode> </children> </node> - <node name="route"> <properties> <help>Reset IPv6 route</help> @@ -76,7 +71,6 @@ </properties> <command>sudo ip -f inet6 route flush cache</command> </leafNode> - <tagNode name="cache"> <properties> <help>Flush the kernel IPv6 route cache for a given route</help> diff --git a/op-mode-definitions/monitor-protocol.xml.in b/op-mode-definitions/monitor-protocol.xml.in index 6a6bd50f3..f3af3575c 100644 --- a/op-mode-definitions/monitor-protocol.xml.in +++ b/op-mode-definitions/monitor-protocol.xml.in @@ -263,13 +263,14 @@ </node> <node name="ospf"> <properties> - <help>Monitor the Open Shortest Path First (OSPF) protocol</help> + <help>Monitor Open Shortest Path First (OSPF) protocol</help> </properties> <children> #include <include/monitor-background.xml.i> - - <node name="disable"> + <properties> + <help>Disable Open Shortest Path First (OSPF) debugging</help> + </properties> <children> <node name="event"> <properties> @@ -458,6 +459,9 @@ </children> </node> <node name="enable"> + <properties> + <help>Enable Open Shortest Path First (OSPF) debugging</help> + </properties> <children> <node name="event"> <properties> diff --git a/op-mode-definitions/nhrp.xml.in b/op-mode-definitions/nhrp.xml.in index 9e746cc35..89508e2be 100644 --- a/op-mode-definitions/nhrp.xml.in +++ b/op-mode-definitions/nhrp.xml.in @@ -50,13 +50,13 @@ <properties> <help>Show NHRP interface connection information</help> </properties> - <command>if [ -f /var/run/opennhrp.pid ]; then sudo opennhrpctl interface show; else echo OpenNHRP is not running.; fi</command> + <command>if pgrep opennhrp >/dev/null; then sudo opennhrpctl interface show; else echo OpenNHRP is not running; fi</command> </leafNode> <leafNode name="tunnel"> <properties> <help>Show NHRP tunnel connection information</help> </properties> - <command>if [ -f /var/run/opennhrp.pid ]; then sudo opennhrpctl show ; else echo OpenNHRP is not running.; fi</command> + <command>if pgrep opennhrp >/dev/null; then sudo opennhrpctl show ; else echo OpenNHRP is not running; fi</command> </leafNode> </children> </node> diff --git a/op-mode-definitions/openvpn.xml.in b/op-mode-definitions/openvpn.xml.in index 781fbdc9d..73cbbe501 100644 --- a/op-mode-definitions/openvpn.xml.in +++ b/op-mode-definitions/openvpn.xml.in @@ -1,11 +1,11 @@ <?xml version="1.0"?> <interfaceDefinition> <node name="reset"> - <properties> - <help>Reset a service</help> - </properties> <children> <node name="openvpn"> + <properties> + <help>Reset OpenVPN client/server connections</help> + </properties> <children> <tagNode name="client"> <properties> diff --git a/op-mode-definitions/pppoe-server.xml.in b/op-mode-definitions/pppoe-server.xml.in index 6efdc5a48..835e03aab 100644 --- a/op-mode-definitions/pppoe-server.xml.in +++ b/op-mode-definitions/pppoe-server.xml.in @@ -40,9 +40,6 @@ </children> </node> <node name="reset"> - <properties> - <help>Reset a service</help> - </properties> <children> <node name="pppoe-server"> <properties> diff --git a/op-mode-definitions/reset-conntrack.xml.in b/op-mode-definitions/reset-conntrack.xml.in index 827ba4af4..9c8265f77 100644 --- a/op-mode-definitions/reset-conntrack.xml.in +++ b/op-mode-definitions/reset-conntrack.xml.in @@ -1,9 +1,6 @@ <?xml version="1.0"?> <interfaceDefinition> <node name="reset"> - <properties> - <help>Reset a service</help> - </properties> <children> <node name="conntrack"> <properties> diff --git a/op-mode-definitions/reset-vpn.xml.in b/op-mode-definitions/reset-vpn.xml.in index 71dbb4ed9..94ee1c7df 100644 --- a/op-mode-definitions/reset-vpn.xml.in +++ b/op-mode-definitions/reset-vpn.xml.in @@ -1,9 +1,6 @@ <?xml version="1.0"?> <interfaceDefinition> <node name="reset"> - <properties> - <help>Reset a service</help> - </properties> <children> <node name="vpn"> <properties> diff --git a/op-mode-definitions/restart-frr.xml.in b/op-mode-definitions/restart-frr.xml.in index 96ad1a650..475bd1ee8 100644 --- a/op-mode-definitions/restart-frr.xml.in +++ b/op-mode-definitions/restart-frr.xml.in @@ -2,62 +2,66 @@ <interfaceDefinition> <node name="restart"> <children> - <node name="frr"> + <leafNode name="all"> <properties> - <help>Restart FRRouting daemons</help> + <help>Restart all routing daemons</help> </properties> <command>sudo ${vyos_op_scripts_dir}/restart_frr.py --action restart</command> - <children> - <leafNode name="bfdd"> - <properties> - <help>Restart Bidirectional Forwarding Detection daemon</help> - </properties> - <command>sudo ${vyos_op_scripts_dir}/restart_frr.py --action restart --daemon bfdd</command> - </leafNode> - <leafNode name="bgpd"> - <properties> - <help>Restart Border Gateway Protocol daemon</help> - </properties> - <command>sudo ${vyos_op_scripts_dir}/restart_frr.py --action restart --daemon bgpd</command> - </leafNode> - <leafNode name="ospfd"> - <properties> - <help>Restart OSPFv2 daemon</help> - </properties> - <command>sudo ${vyos_op_scripts_dir}/restart_frr.py --action restart --daemon ospfd</command> - </leafNode> - <leafNode name="ospf6d"> - <properties> - <help>Restart OSPFv3 daemon</help> - </properties> - <command>sudo ${vyos_op_scripts_dir}/restart_frr.py --action restart --daemon ospf6d</command> - </leafNode> - <leafNode name="ripd"> - <properties> - <help>Restart Routing Information Protocol daemon</help> - </properties> - <command>sudo ${vyos_op_scripts_dir}/restart_frr.py --action restart --daemon ripd</command> - </leafNode> - <leafNode name="ripngd"> - <properties> - <help>Restart RIPng daemon</help> - </properties> - <command>sudo ${vyos_op_scripts_dir}/restart_frr.py --action restart --daemon ripngd</command> - </leafNode> - <leafNode name="staticd"> - <properties> - <help>Restart Static Route daemon</help> - </properties> - <command>sudo ${vyos_op_scripts_dir}/restart_frr.py --action restart --daemon staticd</command> - </leafNode> - <leafNode name="zebra"> - <properties> - <help>Restart IP routing manager daemon</help> - </properties> - <command>sudo ${vyos_op_scripts_dir}/restart_frr.py --action restart --daemon zebra</command> - </leafNode> - </children> - </node> + </leafNode> + <leafNode name="bfd"> + <properties> + <help>Restart Bidirectional Forwarding Detection (BFD) daemon</help> + </properties> + <command>sudo ${vyos_op_scripts_dir}/restart_frr.py --action restart --daemon bfdd</command> + </leafNode> + <leafNode name="bgp"> + <properties> + <help>Restart Border Gateway Protocol (BGP) routing daemon</help> + </properties> + <command>sudo ${vyos_op_scripts_dir}/restart_frr.py --action restart --daemon bgpd</command> + </leafNode> + <leafNode name="isis"> + <properties> + <help>Restart Intermediate System to Intermediate System (IS-IS) routing daemon</help> + </properties> + <command>sudo ${vyos_op_scripts_dir}/restart_frr.py --action restart --daemon isisd</command> + </leafNode> + <leafNode name="ospf"> + <properties> + <help>Restart Open Shortest Path First (OSPF) routing daemon</help> + </properties> + <command>sudo ${vyos_op_scripts_dir}/restart_frr.py --action restart --daemon ospfd</command> + </leafNode> + <leafNode name="ospfv3"> + <properties> + <help>Restart IPv6 Open Shortest Path First (OSPFv3) routing daemon</help> + </properties> + <command>sudo ${vyos_op_scripts_dir}/restart_frr.py --action restart --daemon ospf6d</command> + </leafNode> + <leafNode name="rip"> + <properties> + <help>Restart Routing Information Protocol (RIP) routing daemon</help> + </properties> + <command>sudo ${vyos_op_scripts_dir}/restart_frr.py --action restart --daemon ripd</command> + </leafNode> + <leafNode name="ripng"> + <properties> + <help>Restart Routing Information Protocol NG (RIPng) routing daemon</help> + </properties> + <command>sudo ${vyos_op_scripts_dir}/restart_frr.py --action restart --daemon ripngd</command> + </leafNode> + <leafNode name="static"> + <properties> + <help>Restart static routing daemon</help> + </properties> + <command>sudo ${vyos_op_scripts_dir}/restart_frr.py --action restart --daemon staticd</command> + </leafNode> + <leafNode name="zebra"> + <properties> + <help>Restart Routing Information Base (RIB) manager daemon</help> + </properties> + <command>sudo ${vyos_op_scripts_dir}/restart_frr.py --action restart --daemon zebra</command> + </leafNode> </children> </node> </interfaceDefinition> diff --git a/op-mode-definitions/show-system.xml.in b/op-mode-definitions/show-system.xml.in index 5e9bf719e..18a28868d 100644 --- a/op-mode-definitions/show-system.xml.in +++ b/op-mode-definitions/show-system.xml.in @@ -55,12 +55,6 @@ </properties> <command>${vyos_op_scripts_dir}/show_cpu.py</command> </leafNode> - <leafNode name= "integrity"> - <properties> - <help>Checks overall system integrity</help> - </properties> - <command>sudo ${vyos_op_scripts_dir}/show_system_integrity.py</command> - </leafNode> <leafNode name="kernel-messages"> <properties> <help>Show messages in kernel ring buffer</help> diff --git a/op-mode-definitions/show-vpn.xml.in b/op-mode-definitions/show-vpn.xml.in deleted file mode 100644 index 3fbc74ad1..000000000 --- a/op-mode-definitions/show-vpn.xml.in +++ /dev/null @@ -1,20 +0,0 @@ -<?xml version="1.0"?> -<interfaceDefinition> - <node name="show"> - <children> - <node name="vpn"> - <properties> - <help>Show active remote access Virtual Private Network (VPN) sessions</help> - </properties> - <children> - <leafNode name="remote-access"> - <properties> - <help>Show active VPN server sessions</help> - </properties> - <command>${vyos_op_scripts_dir}/show_vpn_ra.py</command> - </leafNode> - </children> - </node> - </children> - </node> -</interfaceDefinition> diff --git a/op-mode-definitions/terminal.xml.in b/op-mode-definitions/terminal.xml.in index 9c4e629cb..2a76de146 100644 --- a/op-mode-definitions/terminal.xml.in +++ b/op-mode-definitions/terminal.xml.in @@ -40,7 +40,6 @@ </properties> <command>builtin $3</command> </tagNode> - <node name="console"> <properties> <help>Control console behaviors</help> @@ -54,13 +53,11 @@ </leafNode> </children> </node> - <node name="terminal"> <properties> <help>Control terminal behaviors</help> </properties> <children> - <node name="key"> <properties> <help>Set key behaviors</help> @@ -77,7 +74,6 @@ </tagNode> </children> </node> - <node name="pager"> <properties> <help>Set terminal pager to default (less)</help> @@ -93,7 +89,6 @@ </properties> <command>VYATTA_PAGER=$4</command> </tagNode> - <tagNode name="length"> <properties> <help>Set terminal to given number of rows (0 disables paging)</help> @@ -103,7 +98,6 @@ </properties> <command>if [ "$4" -eq 0 ]; then VYATTA_PAGER=cat; else VYATTA_PAGER=${_vyatta_default_pager}; stty rows $4; fi</command> </tagNode> - <tagNode name="width"> <properties> <help>Set terminal to given number of columns</help> @@ -117,6 +111,4 @@ </node> </children> </node> - - </interfaceDefinition> diff --git a/op-mode-definitions/vpn-ipsec.xml.in b/op-mode-definitions/vpn-ipsec.xml.in index 20f275e9b..3d997c143 100644 --- a/op-mode-definitions/vpn-ipsec.xml.in +++ b/op-mode-definitions/vpn-ipsec.xml.in @@ -140,6 +140,12 @@ </properties> <command>sudo ip xfrm policy list</command> </node> + <leafNode name="remote-access"> + <properties> + <help>Show active VPN server sessions</help> + </properties> + <command>${vyos_op_scripts_dir}/show_vpn_ra.py</command> + </leafNode> <node name="sa"> <properties> <help>Show all active IPSec Security Associations (SA)</help> @@ -178,7 +184,7 @@ <command>if pgrep charon >/dev/null ; then sudo /usr/sbin/ipsec statusall ; else echo "IPSec process not running" ; fi</command> </node> </children> - <command>if pgrep charon >/dev/null ; then sudo /usr/libexec/vyos/op_mode/show_ipsec_sa.py ; else echo "IPSec process not running" ; fi</command> + <command>if pgrep charon >/dev/null ; then sudo ${vyos_op_scripts_dir}/show_ipsec_sa.py ; else echo "IPSec process not running" ; fi</command> </node> <node name="state"> <properties> diff --git a/python/vyos/configdict.py b/python/vyos/configdict.py index 0969a5353..e15579b95 100644 --- a/python/vyos/configdict.py +++ b/python/vyos/configdict.py @@ -108,16 +108,20 @@ def leaf_node_changed(conf, path): """ Check if a leaf node was altered. If it has been altered - values has been changed, or it was added/removed, we will return a list containing the old - value(s). If nothing has been changed, None is returned + value(s). If nothing has been changed, None is returned. + + NOTE: path must use the real CLI node name (e.g. with a hyphen!) """ from vyos.configdiff import get_config_diff D = get_config_diff(conf, key_mangling=('-', '_')) D.set_level(conf.get_level()) (new, old) = D.get_value_diff(path) if new != old: + if old is None: + return [''] if isinstance(old, str): return [old] - elif isinstance(old, list): + if isinstance(old, list): if isinstance(new, str): new = [new] elif isinstance(new, type(None)): diff --git a/python/vyos/configverify.py b/python/vyos/configverify.py index 4279e6982..7f49aa9af 100644 --- a/python/vyos/configverify.py +++ b/python/vyos/configverify.py @@ -237,8 +237,8 @@ def verify_interface_exists(ifname): Common helper function used by interface implementations to perform recurring validation if an interface actually exists. """ - from netifaces import interfaces - if ifname not in interfaces(): + import os + if not os.path.exists(f'/sys/class/net/{ifname}'): raise ConfigError(f'Interface "{ifname}" does not exist!') def verify_source_interface(config): diff --git a/python/vyos/defaults.py b/python/vyos/defaults.py index 03006c383..dacdbdef2 100644 --- a/python/vyos/defaults.py +++ b/python/vyos/defaults.py @@ -13,6 +13,7 @@ # 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 directories = { "data": "/usr/share/vyos/", @@ -34,7 +35,7 @@ cfg_vintage = 'vyos' commit_lock = '/opt/vyatta/config/.lock' -version_file = '/usr/share/vyos/component-versions.json' +component_version_json = os.path.join(directories['data'], 'component-versions.json') https_data = { 'listen_addresses' : { '*': ['_'] } diff --git a/python/vyos/ifconfig/bridge.py b/python/vyos/ifconfig/bridge.py index 14f64a8de..27073b266 100644 --- a/python/vyos/ifconfig/bridge.py +++ b/python/vyos/ifconfig/bridge.py @@ -366,5 +366,4 @@ class BridgeIf(Interface): cmd = f'bridge vlan add dev {interface} vid {native_vlan_id} pvid untagged master' self._cmd(cmd) - # call base class first super().update(config) diff --git a/python/vyos/ifconfig/interface.py b/python/vyos/ifconfig/interface.py index a1928ba51..45a220e22 100755 --- a/python/vyos/ifconfig/interface.py +++ b/python/vyos/ifconfig/interface.py @@ -52,6 +52,10 @@ from vyos.ifconfig.vrrp import VRRP from vyos.ifconfig.operational import Operational from vyos.ifconfig import Section +from netaddr import EUI +from netaddr import mac_unix_expanded +from random import getrandbits + class Interface(Control): # This is the class which will be used to create # self.operational, it allows subclasses, such as @@ -389,6 +393,31 @@ class Interface(Control): """ return self.get_interface('mac') + def get_mac_synthetic(self): + """ + Get a synthetic MAC address. This is a common method which can be called + from derived classes to overwrite the get_mac() call in a generic way. + + NOTE: Tunnel interfaces have no "MAC" address by default. The content + of the 'address' file in /sys/class/net/device contains the + local-ip thus we generate a random MAC address instead + + Example: + >>> from vyos.ifconfig import Interface + >>> Interface('eth0').get_mac() + '00:50:ab:cd:ef:00' + """ + # we choose 40 random bytes for the MAC address, this gives + # us e.g. EUI('00-EA-EE-D6-A3-C8') or EUI('00-41-B9-0D-F2-2A') + tmp = EUI(getrandbits(48)).value + # set locally administered bit in MAC address + tmp |= 0xf20000000000 + # convert integer to "real" MAC address representation + mac = EUI(hex(tmp).split('x')[-1]) + # change dialect to use : as delimiter instead of - + mac.dialect = mac_unix_expanded + return str(mac) + def set_mac(self, mac): """ Set interface MAC (Media Access Contrl) address to given value. @@ -436,6 +465,62 @@ class Interface(Control): """ return self.set_interface('arp_cache_tmo', tmo) + def set_tcp_ipv4_mss(self, mss): + """ + Set IPv4 TCP MSS value advertised when TCP SYN packets leave this + interface. Value is in bytes. + + A value of 0 will disable the MSS adjustment + + Example: + >>> from vyos.ifconfig import Interface + >>> Interface('eth0').set_tcp_ipv4_mss(1340) + """ + iptables_bin = 'iptables' + base_options = f'-A FORWARD -o {self.ifname} -p tcp -m tcp --tcp-flags SYN,RST SYN' + out = self._cmd(f'{iptables_bin}-save -t mangle') + for line in out.splitlines(): + if line.startswith(base_options): + # remove OLD MSS mangling configuration + line = line.replace('-A FORWARD', '-D FORWARD') + self._cmd(f'{iptables_bin} -t mangle {line}') + + cmd_mss = f'{iptables_bin} -t mangle {base_options} --jump TCPMSS' + if mss == 'clamp-mss-to-pmtu': + self._cmd(f'{cmd_mss} --clamp-mss-to-pmtu') + elif int(mss) > 0: + # probably add option to clamp only if bigger: + low_mss = str(int(mss) + 1) + self._cmd(f'{cmd_mss} -m tcpmss --mss {low_mss}:65535 --set-mss {mss}') + + def set_tcp_ipv6_mss(self, mss): + """ + Set IPv6 TCP MSS value advertised when TCP SYN packets leave this + interface. Value is in bytes. + + A value of 0 will disable the MSS adjustment + + Example: + >>> from vyos.ifconfig import Interface + >>> Interface('eth0').set_tcp_mss(1320) + """ + iptables_bin = 'ip6tables' + base_options = f'-A FORWARD -o {self.ifname} -p tcp -m tcp --tcp-flags SYN,RST SYN' + out = self._cmd(f'{iptables_bin}-save -t mangle') + for line in out.splitlines(): + if line.startswith(base_options): + # remove OLD MSS mangling configuration + line = line.replace('-A FORWARD', '-D FORWARD') + self._cmd(f'{iptables_bin} -t mangle {line}') + + cmd_mss = f'{iptables_bin} -t mangle {base_options} --jump TCPMSS' + if mss == 'clamp-mss-to-pmtu': + self._cmd(f'{cmd_mss} --clamp-mss-to-pmtu') + elif int(mss) > 0: + # probably add option to clamp only if bigger: + low_mss = str(int(mss) + 1) + self._cmd(f'{cmd_mss} -m tcpmss --mss {low_mss}:65535 --set-mss {mss}') + def set_arp_filter(self, arp_filter): """ Filter ARP requests @@ -1202,6 +1287,16 @@ class Interface(Control): # checked before self.set_vrf(config.get('vrf', '')) + # Configure MSS value for IPv4 TCP connections + tmp = dict_search('ip.adjust_mss', config) + value = tmp if (tmp != None) else '0' + self.set_tcp_ipv4_mss(value) + + # Configure MSS value for IPv6 TCP connections + tmp = dict_search('ipv6.adjust_mss', config) + value = tmp if (tmp != None) else '0' + self.set_tcp_ipv6_mss(value) + # Configure ARP cache timeout in milliseconds - has default value tmp = dict_search('ip.arp_cache_timeout', config) value = tmp if (tmp != None) else '30' diff --git a/python/vyos/ifconfig/pppoe.py b/python/vyos/ifconfig/pppoe.py index 65575cf99..9153863de 100644 --- a/python/vyos/ifconfig/pppoe.py +++ b/python/vyos/ifconfig/pppoe.py @@ -1,4 +1,4 @@ -# Copyright 2020 VyOS maintainers and contributors <maintainers@vyos.io> +# Copyright 2020-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 @@ -14,12 +14,11 @@ # License along with this library. If not, see <http://www.gnu.org/licenses/>. from vyos.ifconfig.interface import Interface +from vyos.util import get_interface_config @Interface.register class PPPoEIf(Interface): - default = { - 'type': 'pppoe', - } + iftype = 'pppoe' definition = { **Interface.definition, **{ @@ -28,7 +27,31 @@ class PPPoEIf(Interface): }, } - # stub this interface is created in the configure script + def _remove_routes(self, vrf=''): + # Always delete default routes when interface is removed + if vrf: + vrf = f'-c "vrf {vrf}"' + self._cmd(f'vtysh -c "conf t" {vrf} -c "no ip route 0.0.0.0/0 {self.ifname} tag 210"') + self._cmd(f'vtysh -c "conf t" {vrf} -c "no ipv6 route ::/0 {self.ifname} tag 210"') + + def remove(self): + """ + Remove interface from operating system. Removing the interface + deconfigures all assigned IP addresses and clear possible DHCP(v6) + client processes. + Example: + >>> from vyos.ifconfig import Interface + >>> i = Interface('pppoe0') + >>> i.remove() + """ + + tmp = get_interface_config(self.ifname) + vrf = '' + if 'master' in tmp: + self._remove_routes(tmp['master']) + + # remove bond master which places members in disabled state + super().remove() def _create(self): # we can not create this interface as it is managed outside @@ -37,3 +60,84 @@ class PPPoEIf(Interface): def _delete(self): # we can not create this interface as it is managed outside pass + + def del_addr(self, addr): + # we can not create this interface as it is managed outside + pass + + def get_mac(self): + """ Get a synthetic MAC address. """ + return self.get_mac_synthetic() + + def update(self, config): + """ General helper function which works on a dictionary retrived by + get_config_dict(). It's main intention is to consolidate the scattered + interface setup code and provide a single point of entry when workin + on any interface. """ + + # remove old routes from an e.g. old VRF assignment + vrf = '' + if 'vrf_old' in config: + vrf = config['vrf_old'] + self._remove_routes(vrf) + + # DHCPv6 PD handling is a bit different on PPPoE interfaces, as we do + # not require an 'address dhcpv6' CLI option as with other interfaces + if 'dhcpv6_options' in config and 'pd' in config['dhcpv6_options']: + self.set_dhcpv6(True) + else: + self.set_dhcpv6(False) + + super().update(config) + + if 'default_route' not in config or config['default_route'] == 'none': + return + + # + # Set default routes pointing to pppoe interface + # + vrf = '' + sed_opt = '^ip route' + + install_v4 = True + install_v6 = True + + # generate proper configuration string when VRFs are in use + if 'vrf' in config: + tmp = config['vrf'] + vrf = f'-c "vrf {tmp}"' + sed_opt = f'vrf {tmp}' + + if config['default_route'] == 'auto': + # only add route if there is no default route present + tmp = self._cmd(f'vtysh -c "show running-config staticd no-header" | sed -n "/{sed_opt}/,/!/p"') + for line in tmp.splitlines(): + line = line.lstrip() + if line.startswith('ip route 0.0.0.0/0'): + install_v4 = False + continue + + if 'ipv6' in config and line.startswith('ipv6 route ::/0'): + install_v6 = False + continue + + elif config['default_route'] == 'force': + # Force means that all static routes are replaced with the ones from this interface + tmp = self._cmd(f'vtysh -c "show running-config staticd no-header" | sed -n "/{sed_opt}/,/!/p"') + for line in tmp.splitlines(): + if self.ifname in line: + # It makes no sense to remove a route with our interface and the later re-add it. + # This will only make traffic disappear - which is a no-no! + continue + + line = line.lstrip() + if line.startswith('ip route 0.0.0.0/0'): + self._cmd(f'vtysh -c "conf t" {vrf} -c "no {line}"') + + if 'ipv6' in config and line.startswith('ipv6 route ::/0'): + self._cmd(f'vtysh -c "conf t" {vrf} -c "no {line}"') + + if install_v4: + self._cmd(f'vtysh -c "conf t" {vrf} -c "ip route 0.0.0.0/0 {self.ifname} tag 210"') + if install_v6 and 'ipv6' in config: + self._cmd(f'vtysh -c "conf t" {vrf} -c "ipv6 route ::/0 {self.ifname} tag 210"') diff --git a/python/vyos/ifconfig/section.py b/python/vyos/ifconfig/section.py index 173a90bb4..0e4447b9e 100644 --- a/python/vyos/ifconfig/section.py +++ b/python/vyos/ifconfig/section.py @@ -46,7 +46,7 @@ class Section: return klass @classmethod - def _basename (cls, name, vlan): + def _basename(cls, name, vlan, vrrp): """ remove the number at the end of interface name name: name of the interface @@ -56,16 +56,18 @@ class Section: name = name.rstrip('.') if vlan: name = name.rstrip('0123456789.') + if vrrp: + name = name.rstrip('0123456789v') return name @classmethod - def section(cls, name, vlan=True): + def section(cls, name, vlan=True, vrrp=True): """ return the name of a section an interface should be under name: name of the interface (eth0, dum1, ...) vlan: should we try try to remove the VLAN from the number """ - name = cls._basename(name, vlan) + name = cls._basename(name, vlan, vrrp) if name in cls._prefixes: return cls._prefixes[name].definition['section'] @@ -79,8 +81,8 @@ class Section: return list(set([cls._prefixes[_].definition['section'] for _ in cls._prefixes])) @classmethod - def klass(cls, name, vlan=True): - name = cls._basename(name, vlan) + def klass(cls, name, vlan=True, vrrp=True): + name = cls._basename(name, vlan, vrrp) if name in cls._prefixes: return cls._prefixes[name] raise ValueError(f'No type found for interface name: {name}') diff --git a/python/vyos/ifconfig/tunnel.py b/python/vyos/ifconfig/tunnel.py index 64c735824..5258a2cb1 100644 --- a/python/vyos/ifconfig/tunnel.py +++ b/python/vyos/ifconfig/tunnel.py @@ -16,10 +16,6 @@ # https://developers.redhat.com/blog/2019/05/17/an-introduction-to-linux-virtual-interfaces-tunnels/ # https://community.hetzner.com/tutorials/linux-setup-gre-tunnel -from netaddr import EUI -from netaddr import mac_unix_expanded -from random import getrandbits - from vyos.ifconfig.interface import Interface from vyos.util import dict_search from vyos.validate import assert_list @@ -163,28 +159,8 @@ class TunnelIf(Interface): self._cmd(cmd.format(**self.config)) def get_mac(self): - """ - Get current interface MAC (Media Access Contrl) address used. - - NOTE: Tunnel interfaces have no "MAC" address by default. The content - of the 'address' file in /sys/class/net/device contains the - local-ip thus we generate a random MAC address instead - - Example: - >>> from vyos.ifconfig import Interface - >>> Interface('eth0').get_mac() - '00:50:ab:cd:ef:00' - """ - # we choose 40 random bytes for the MAC address, this gives - # us e.g. EUI('00-EA-EE-D6-A3-C8') or EUI('00-41-B9-0D-F2-2A') - tmp = EUI(getrandbits(48)).value - # set locally administered bit in MAC address - tmp |= 0xf20000000000 - # convert integer to "real" MAC address representation - mac = EUI(hex(tmp).split('x')[-1]) - # change dialect to use : as delimiter instead of - - mac.dialect = mac_unix_expanded - return str(mac) + """ Get a synthetic MAC address. """ + return self.get_mac_synthetic() def update(self, config): """ General helper function which works on a dictionary retrived by diff --git a/python/vyos/ifconfig/wireguard.py b/python/vyos/ifconfig/wireguard.py index c4cf2fbbf..28b5e2991 100644 --- a/python/vyos/ifconfig/wireguard.py +++ b/python/vyos/ifconfig/wireguard.py @@ -17,9 +17,6 @@ import os import time from datetime import timedelta -from netaddr import EUI -from netaddr import mac_unix_expanded -from random import getrandbits from hurry.filesize import size from hurry.filesize import alternative @@ -159,28 +156,8 @@ class WireGuardIf(Interface): } def get_mac(self): - """ - Get current interface MAC (Media Access Contrl) address used. - - NOTE: Tunnel interfaces have no "MAC" address by default. The content - of the 'address' file in /sys/class/net/device contains the - local-ip thus we generate a random MAC address instead - - Example: - >>> from vyos.ifconfig import Interface - >>> Interface('eth0').get_mac() - '00:50:ab:cd:ef:00' - """ - # we choose 40 random bytes for the MAC address, this gives - # us e.g. EUI('00-EA-EE-D6-A3-C8') or EUI('00-41-B9-0D-F2-2A') - tmp = EUI(getrandbits(48)).value - # set locally administered bit in MAC address - tmp |= 0xf20000000000 - # convert integer to "real" MAC address representation - mac = EUI(hex(tmp).split('x')[-1]) - # change dialect to use : as delimiter instead of - - mac.dialect = mac_unix_expanded - return str(mac) + """ Get a synthetic MAC address. """ + return self.get_mac_synthetic() def update(self, config): """ General helper function which works on a dictionary retrived by diff --git a/python/vyos/migrator.py b/python/vyos/migrator.py index 9a5fdef2f..4574bb6d1 100644 --- a/python/vyos/migrator.py +++ b/python/vyos/migrator.py @@ -15,6 +15,7 @@ import sys import os +import json import subprocess import vyos.version import vyos.defaults @@ -165,6 +166,20 @@ class Migrator(object): versions_string, os_version_string) + def save_json_record(self, component_versions: dict): + """ + Write component versions to a json file + """ + mask = os.umask(0o113) + version_file = vyos.defaults.component_version_json + try: + with open(version_file, 'w') as f: + f.write(json.dumps(component_versions, indent=2, sort_keys=True)) + except OSError: + pass + finally: + os.umask(mask) + def run(self): """ Gather component versions from config file and system. @@ -182,6 +197,9 @@ class Migrator(object): sys_versions = systemversions.get_system_versions() + # save system component versions in json file for easy reference + self.save_json_record(sys_versions) + rev_versions = self.run_migration_scripts(cfg_versions, sys_versions) if rev_versions != cfg_versions: diff --git a/python/vyos/systemversions.py b/python/vyos/systemversions.py index 5c4deca29..9b3f4f413 100644 --- a/python/vyos/systemversions.py +++ b/python/vyos/systemversions.py @@ -16,15 +16,12 @@ import os import re import sys -import json - import vyos.defaults def get_system_versions(): """ - Get component versions from running system: read vyatta directory - structure for versions, then read vyos JSON file. It is a critical - error if either migration directory or JSON file is unreadable. + Get component versions from running system; critical failure if + unable to read migration directory. """ system_versions = {} @@ -39,25 +36,4 @@ def get_system_versions(): pair = info.split('@') system_versions[pair[0]] = int(pair[1]) - version_dict = {} - path = vyos.defaults.version_file - - if os.path.isfile(path): - with open(path, 'r') as f: - try: - version_dict = json.load(f) - except ValueError as err: - print(f"\nValue error in {path}: {err}") - sys.exit(1) - - for k, v in version_dict.items(): - if not isinstance(v, int): - print(f"\nType error in {path}; expecting Dict[str, int]") - sys.exit(1) - existing = system_versions.get(k) - if existing is None: - system_versions[k] = v - elif v > existing: - system_versions[k] = v - return system_versions diff --git a/python/vyos/template.py b/python/vyos/template.py index 08a5712af..ee6e52e1d 100644 --- a/python/vyos/template.py +++ b/python/vyos/template.py @@ -406,7 +406,7 @@ def get_esp_ike_cipher(group_config): 'dh-group18' : 'modp8192', 'dh-group19' : 'ecp256', 'dh-group20' : 'ecp384', - 'dh-group21' : 'ecp512', + 'dh-group21' : 'ecp521', 'dh-group22' : 'modp1024s160', 'dh-group23' : 'modp2048s224', 'dh-group24' : 'modp2048s256', diff --git a/python/vyos/util.py b/python/vyos/util.py index 59f9f1c44..8af46a6ee 100644 --- a/python/vyos/util.py +++ b/python/vyos/util.py @@ -562,12 +562,13 @@ def commit_in_progress(): # Since this will be used in scripts that modify the config outside of the CLI # framework, those knowingly have root permissions. # For everything else, we add a safeguard. - from psutil import process_iter, NoSuchProcess + from psutil import process_iter + from psutil import NoSuchProcess + from getpass import getuser from vyos.defaults import commit_lock - idu = cmd('/usr/bin/id -u') - if idu != '0': - raise OSError("This functions needs root permissions to return correct results") + if getuser() != 'root': + raise OSError('This functions needs to be run as root to return correct results!') for proc in process_iter(): try: @@ -805,8 +806,16 @@ def make_incremental_progressbar(increment: float): while True: yield +def is_systemd_service_active(service): + """ Test is a specified systemd service is activated. + Returns True if service is active, false otherwise. + Copied from: https://unix.stackexchange.com/a/435317 """ + tmp = cmd(f'systemctl show --value -p ActiveState {service}') + return bool((tmp == 'active')) + def is_systemd_service_running(service): """ Test is a specified systemd service is actually running. - Returns True if service is running, false otherwise. """ - tmp = run(f'systemctl is-active --quiet {service}') - return bool((tmp == 0)) + Returns True if service is running, false otherwise. + Copied from: https://unix.stackexchange.com/a/435317 """ + tmp = cmd(f'systemctl show --value -p SubState {service}') + return bool((tmp == 'running')) diff --git a/python/vyos/xml/__init__.py b/python/vyos/xml/__init__.py index 0ef0c85ce..e0eacb2d1 100644 --- a/python/vyos/xml/__init__.py +++ b/python/vyos/xml/__init__.py @@ -46,6 +46,8 @@ def is_tag(lpath): def is_leaf(lpath, flat=True): return load_configuration().is_leaf(lpath, flat) +def component_versions(): + return load_configuration().component_versions() def defaults(lpath, flat=False): return load_configuration().defaults(lpath, flat) diff --git a/python/vyos/xml/definition.py b/python/vyos/xml/definition.py index f556c5ced..5e0d5282c 100644 --- a/python/vyos/xml/definition.py +++ b/python/vyos/xml/definition.py @@ -30,6 +30,7 @@ class XML(dict): self[kw.owners] = {} self[kw.default] = {} self[kw.tags] = [] + self[kw.component_version] = {} dict.__init__(self) @@ -248,6 +249,11 @@ class XML(dict): # @lru_cache(maxsize=100) # XXX: need to use cachetool instead - for later + def component_versions(self) -> dict: + sort_component = sorted(self[kw.component_version].items(), + key = lambda kv: kv[0]) + return dict(sort_component) + def defaults(self, lpath, flat): d = self[kw.default] for k in lpath: diff --git a/python/vyos/xml/kw.py b/python/vyos/xml/kw.py index 58d47e751..48226ce96 100644 --- a/python/vyos/xml/kw.py +++ b/python/vyos/xml/kw.py @@ -32,6 +32,7 @@ priorities = '[priorities]' owners = '[owners]' tags = '[tags]' default = '[default]' +component_version = '[component_version]' # nodes diff --git a/python/vyos/xml/load.py b/python/vyos/xml/load.py index 37479c6e1..c3022f3d6 100644 --- a/python/vyos/xml/load.py +++ b/python/vyos/xml/load.py @@ -115,7 +115,12 @@ def _format_nodes(inside, conf, xml): nodetype = 'tagNode' nodename = kw.tagNode elif 'syntaxVersion' in conf.keys(): - conf.pop('syntaxVersion') + sv = conf.pop('syntaxVersion') + if isinstance(sv, list): + for v in sv: + xml[kw.component_version][v['@component']] = v['@version'] + else: + xml[kw.component_version][sv['@component']] = sv['@version'] continue else: _fatal(conf.keys()) @@ -125,14 +130,20 @@ def _format_nodes(inside, conf, xml): for node in nodes: name = node.pop('@name') into = inside + [name] - r[name] = _format_node(into, node, xml) + if name in r: + r[name].update(_format_node(into, node, xml)) + else: + r[name] = _format_node(into, node, xml) r[name][kw.node] = nodename xml[kw.tags].append(' '.join(into)) else: node = nodes name = node.pop('@name') into = inside + [name] - r[name] = _format_node(inside + [name], node, xml) + if name in r: + r[name].update(_format_node(inside + [name], node, xml)) + else: + r[name] = _format_node(inside + [name], node, xml) r[name][kw.node] = nodename xml[kw.tags].append(' '.join(into)) return r diff --git a/scripts/build-command-op-templates b/scripts/build-command-op-templates index c285ee594..a4d6d1d08 100755 --- a/scripts/build-command-op-templates +++ b/scripts/build-command-op-templates @@ -54,7 +54,7 @@ debug = args.debug try: xml = ET.parse(input_file) except Exception as e: - print("Failed to load interface definition file {0}".format(input_file)) + print(f"Failed to load interface definition file {input_file}") print(e) sys.exit(1) @@ -64,15 +64,15 @@ try: if not validator.validate(xml): print(validator.error_log) - print("Interface definition file {0} does not match the schema!".format(input_file)) + print(f"Interface definition file {input_file} does not match the schema!") sys.exit(1) except Exception as e: - print("Failed to load the XML schema {0}".format(schema_file)) + print(f"Failed to load the XML schema {schema_file}") print(e) sys.exit(1) if not os.access(output_dir, os.W_OK): - print("The output directory {0} is not writeable".format(output_dir)) + print(f"The output directory {output_dir} is not writeable") sys.exit(1) ## If we got this far, everything must be ok and we can convert the file @@ -160,16 +160,16 @@ def process_node(n, tmpl_dir): my_tmpl_dir.append(name) if debug: - print("Name of the node: {};\n Created directory: ".format(name), end="") + print(f"Name of the node: {name};\n Created directory: ", end="") os.makedirs(make_path(my_tmpl_dir), exist_ok=True) props = get_properties(props_elem) + nodedef_path = os.path.join(make_path(my_tmpl_dir), "node.def") if node_type == "node": if debug: - print("Processing node {}".format(name)) + print(f"Processing node {name}") - nodedef_path = os.path.join(make_path(my_tmpl_dir), "node.def") # Only create the "node.def" file if it exists but is empty, or if it # does not exist at all. if not os.path.exists(nodedef_path) or os.path.getsize(nodedef_path) == 0: @@ -180,19 +180,18 @@ def process_node(n, tmpl_dir): inner_nodes = children.iterfind("*") for inner_n in inner_nodes: process_node(inner_n, my_tmpl_dir) + if node_type == "tagNode": if debug: - print("Processing tag node {}".format(name)) + print(f"Processing tagNode {name}") os.makedirs(make_path(my_tmpl_dir), exist_ok=True) - nodedef_path = os.path.join(make_path(my_tmpl_dir), "node.def") - if not os.path.exists(nodedef_path): + # Only create the "node.def" file if it exists but is empty, or if it + # does not exist at all. + if not os.path.exists(nodedef_path) or os.path.getsize(nodedef_path) == 0: with open(nodedef_path, "w") as f: f.write('help: {0}\n'.format(props['help'])) - else: - # Something has already generated this file - pass # Create the inner node.tag part my_tmpl_dir.append("node.tag") @@ -201,8 +200,12 @@ def process_node(n, tmpl_dir): print("Created path for the tagNode: {}".format(make_path(my_tmpl_dir)), end="") # Not sure if we want partially defined tag nodes, write the file unconditionally - with open(os.path.join(make_path(my_tmpl_dir), "node.def"), "w") as f: - f.write(make_node_def(props, command)) + nodedef_path = os.path.join(make_path(my_tmpl_dir), "node.def") + # Only create the "node.def" file if it exists but is empty, or if it + # does not exist at all. + if not os.path.exists(nodedef_path) or os.path.getsize(nodedef_path) == 0: + with open(nodedef_path, "w") as f: + f.write(make_node_def(props, command)) if children is not None: inner_nodes = children.iterfind("*") @@ -211,11 +214,11 @@ def process_node(n, tmpl_dir): else: # This is a leaf node if debug: - print("Processing leaf node {}".format(name)) - - with open(os.path.join(make_path(my_tmpl_dir), "node.def"), "w") as f: - f.write(make_node_def(props, command)) + print(f"Processing leaf node {name}") + if not os.path.exists(nodedef_path) or os.path.getsize(nodedef_path) == 0: + with open(nodedef_path, "w") as f: + f.write(make_node_def(props, command)) root = xml.getroot() diff --git a/scripts/build-component-versions b/scripts/build-component-versions deleted file mode 100755 index 5362dbdd4..000000000 --- a/scripts/build-component-versions +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/env python3 - -import sys -import os -import argparse -import json - -from lxml import etree as ET - -parser = argparse.ArgumentParser() -parser.add_argument('INPUT_DIR', type=str, - help="Directory containing XML interface definition files") -parser.add_argument('OUTPUT_DIR', type=str, - help="Output directory for JSON file") - -args = parser.parse_args() - -input_dir = args.INPUT_DIR -output_dir = args.OUTPUT_DIR - -version_dict = {} - -for filename in os.listdir(input_dir): - filepath = os.path.join(input_dir, filename) - print(filepath) - try: - xml = ET.parse(filepath) - except Exception as e: - print("Failed to load interface definition file {0}".format(filename)) - print(e) - sys.exit(1) - - root = xml.getroot() - version_data = root.iterfind("syntaxVersion") - for ver in version_data: - component = ver.get("component") - version = int(ver.get("version")) - - v = version_dict.get(component) - if v is None: - version_dict[component] = version - elif version > v: - version_dict[component] = version - -out_file = os.path.join(output_dir, 'component-versions.json') -with open(out_file, 'w') as f: - json.dump(version_dict, f, indent=4, sort_keys=True) diff --git a/scripts/override-default b/scripts/override-default index c8a0ff1da..0c49087c8 100755 --- a/scripts/override-default +++ b/scripts/override-default @@ -27,6 +27,7 @@ import sys import glob import logging +from copy import deepcopy from lxml import etree debug = False @@ -60,30 +61,55 @@ def override_element(l: list): for el in parents: el.getparent().remove(el) +def merge_remaining(l: list, elementtree): + """ + Merge (now) single leaf node containing 'defaultValue' with leaf nodes + of same path and no 'defaultValue'. + """ + for p in l: + p = p.split() + path_str = f'/interfaceDefinition/*' + path_list = [] + for i in range(len(p)): + path_list.append(f'[@name="{p[i]}"]') + path_str += '/children/*'.join(path_list) + rp = elementtree.xpath(path_str) + if len(rp) > 1: + for el in rp[1:]: + # in practice there will only be one child of the path, + # either defaultValue or Properties, since + # override_element() has already run + for child in el: + rp[0].append(deepcopy(child)) + el.getparent().remove(el) + def collect_and_override(dir_name): """ - Collect elements with defaultValue tag into dictionary indexed by tuple - of (name: str, ancestor path: str). + Collect elements with defaultValue tag into dictionary indexed by name + attributes of ancestor path. """ for fname in glob.glob(f'{dir_name}/*.xml'): tree = etree.parse(fname) root = tree.getroot() defv = {} - xpath_str = f'//defaultValue' + xpath_str = '//defaultValue' xp = tree.xpath(xpath_str) for element in xp: ap = element.xpath('ancestor::*[@name]') ap_name = [el.get("name") for el in ap] - ap_path_str = ' '.join(ap_name[:-1]) - defv.setdefault((ap_name[-1], ap_path_str), []).append(element) + ap_path_str = ' '.join(ap_name) + defv.setdefault(ap_path_str, []).append(element) for k, v in defv.items(): if len(v) > 1: - logger.info(f"overridding default in {k[0]}, path '{k[1]}'") + logger.info(f"overridding default in path '{k}'") override_element(v) + to_merge = list(defv) + merge_remaining(to_merge, tree) + revised_str = etree.tostring(root, encoding='unicode', pretty_print=True) with open(f'{fname}', 'w') as f: diff --git a/smoketest/configs/isis-small b/smoketest/configs/isis-small index 2c42ac9c4..247ae32b5 100644 --- a/smoketest/configs/isis-small +++ b/smoketest/configs/isis-small @@ -102,4 +102,3 @@ system { // Warning: Do not remove the following line. // vyos-config-version: "broadcast-relay@1:cluster@1:config-management@1:conntrack@1:conntrack-sync@1:dhcp-relay@2:dhcp-server@5:dhcpv6-server@1:dns-forwarding@3:firewall@5:https@2:interfaces@18:ipoe-server@1:ipsec@5:l2tp@3:lldp@1:mdns@1:nat@5:ntp@1:pppoe-server@5:pptp@2:qos@1:quagga@7:rpki@1:salt@1:snmp@2:ssh@2:sstp@3:system@20:vrrp@2:vyos-accel-ppp@2:wanloadbalance@3:webproxy@2:zone-policy@1" // Release version: 1.3.0-rc1 - diff --git a/smoketest/scripts/cli/base_interfaces_test.py b/smoketest/scripts/cli/base_interfaces_test.py index 7f69b8444..edb604dbf 100644 --- a/smoketest/scripts/cli/base_interfaces_test.py +++ b/smoketest/scripts/cli/base_interfaces_test.py @@ -556,13 +556,16 @@ class BasicInterfaceTest: if not self._test_ip: self.skipTest('not supported') + arp_tmo = '300' + mss = '1420' + for interface in self._interfaces: - arp_tmo = '300' path = self._base_path + [interface] for option in self._options.get(interface, []): self.cli_set(path + option.split()) # Options + self.cli_set(path + ['ip', 'adjust-mss', mss]) self.cli_set(path + ['ip', 'arp-cache-timeout', arp_tmo]) self.cli_set(path + ['ip', 'disable-arp-filter']) self.cli_set(path + ['ip', 'disable-forwarding']) @@ -576,54 +579,73 @@ class BasicInterfaceTest: self.cli_commit() for interface in self._interfaces: + base_options = f'-A FORWARD -o {interface} -p tcp -m tcp --tcp-flags SYN,RST SYN' + out = cmd('sudo iptables-save -t mangle') + for line in out.splitlines(): + if line.startswith(base_options): + self.assertIn(f'--set-mss {mss}', line) + tmp = read_file(f'/proc/sys/net/ipv4/neigh/{interface}/base_reachable_time_ms') self.assertEqual(tmp, str((int(arp_tmo) * 1000))) # tmo value is in milli seconds - tmp = read_file(f'/proc/sys/net/ipv4/conf/{interface}/arp_filter') + proc_base = f'/proc/sys/net/ipv4/conf/{interface}' + + tmp = read_file(f'{proc_base}/arp_filter') self.assertEqual('0', tmp) - tmp = read_file(f'/proc/sys/net/ipv4/conf/{interface}/arp_accept') + tmp = read_file(f'{proc_base}/arp_accept') self.assertEqual('1', tmp) - tmp = read_file(f'/proc/sys/net/ipv4/conf/{interface}/arp_announce') + tmp = read_file(f'{proc_base}/arp_announce') self.assertEqual('1', tmp) - tmp = read_file(f'/proc/sys/net/ipv4/conf/{interface}/arp_ignore') + tmp = read_file(f'{proc_base}/arp_ignore') self.assertEqual('1', tmp) - tmp = read_file(f'/proc/sys/net/ipv4/conf/{interface}/forwarding') + tmp = read_file(f'{proc_base}/forwarding') self.assertEqual('0', tmp) - tmp = read_file(f'/proc/sys/net/ipv4/conf/{interface}/proxy_arp') + tmp = read_file(f'{proc_base}/proxy_arp') self.assertEqual('1', tmp) - tmp = read_file(f'/proc/sys/net/ipv4/conf/{interface}/proxy_arp_pvlan') + tmp = read_file(f'{proc_base}/proxy_arp_pvlan') self.assertEqual('1', tmp) - tmp = read_file(f'/proc/sys/net/ipv4/conf/{interface}/rp_filter') + tmp = read_file(f'{proc_base}/rp_filter') self.assertEqual('2', tmp) def test_interface_ipv6_options(self): if not self._test_ipv6: self.skipTest('not supported') + mss = '1400' + dad_transmits = '10' + for interface in self._interfaces: - dad_transmits = '10' path = self._base_path + [interface] for option in self._options.get(interface, []): self.cli_set(path + option.split()) # Options + self.cli_set(path + ['ipv6', 'adjust-mss', mss]) self.cli_set(path + ['ipv6', 'disable-forwarding']) self.cli_set(path + ['ipv6', 'dup-addr-detect-transmits', dad_transmits]) self.cli_commit() for interface in self._interfaces: - tmp = read_file(f'/proc/sys/net/ipv6/conf/{interface}/forwarding') + base_options = f'-A FORWARD -o {interface} -p tcp -m tcp --tcp-flags SYN,RST SYN' + out = cmd('sudo ip6tables-save -t mangle') + for line in out.splitlines(): + if line.startswith(base_options): + self.assertIn(f'--set-mss {mss}', line) + + proc_base = f'/proc/sys/net/ipv6/conf/{interface}' + + tmp = read_file(f'{proc_base}/forwarding') self.assertEqual('0', tmp) - tmp = read_file(f'/proc/sys/net/ipv6/conf/{interface}/dad_transmits') + tmp = read_file(f'{proc_base}/dad_transmits') self.assertEqual(dad_transmits, tmp) def test_dhcpv6_client_options(self): diff --git a/smoketest/scripts/cli/base_vyostest_shim.py b/smoketest/scripts/cli/base_vyostest_shim.py index 18e49f47f..50f80e7d1 100644 --- a/smoketest/scripts/cli/base_vyostest_shim.py +++ b/smoketest/scripts/cli/base_vyostest_shim.py @@ -20,7 +20,9 @@ from time import sleep from vyos.configsession import ConfigSession from vyos.configsession import ConfigSessionError from vyos import ConfigError +from vyos.defaults import commit_lock from vyos.util import cmd +from vyos.util import run save_config = '/tmp/vyos-smoketest-save' @@ -70,21 +72,16 @@ class VyOSUnitTestSHIM: def cli_commit(self): self._session.commit() + # during a commit there is a process opening commit_lock, and run() returns 0 + while run(f'sudo lsof | grep -q {commit_lock}') == 0: + sleep(0.250) - def getFRRconfig(self, string, end='$', endsection='^!'): + def getFRRconfig(self, string, end='$', endsection='^!', daemon=''): """ Retrieve current "running configuration" from FRR """ - command = f'vtysh -c "show run" | sed -n "/^{string}{end}/,/{endsection}/p"' - - count = 0 - tmp = '' - while count < 10 and tmp == '': - # Let FRR settle after a config change first before harassing it again - sleep(1) - tmp = cmd(command) - count += 1 - - if self.debug or tmp == '': + command = f'vtysh -c "show run {daemon} no-header" | sed -n "/^{string}{end}/,/{endsection}/p"' + out = cmd(command) + if self.debug: import pprint print(f'\n\ncommand "{command}" returned:\n') - pprint.pprint(tmp) - return tmp + pprint.pprint(out) + return out diff --git a/smoketest/scripts/cli/test_interfaces_pppoe.py b/smoketest/scripts/cli/test_interfaces_pppoe.py index 3412ebae0..67edce2a0 100755 --- a/smoketest/scripts/cli/test_interfaces_pppoe.py +++ b/smoketest/scripts/cli/test_interfaces_pppoe.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2019-2020 VyOS maintainers and contributors +# Copyright (C) 2019-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 @@ -22,10 +22,8 @@ from base_vyostest_shim import VyOSUnitTestSHIM from vyos.configsession import ConfigSession from vyos.configsession import ConfigSessionError -from vyos.util import read_file config_file = '/etc/ppp/peers/{}' -dhcp6c_config_file = '/run/dhcp6c/dhcp6c.{}.conf' base_path = ['interfaces', 'pppoe'] def get_config_value(interface, key): @@ -35,25 +33,26 @@ def get_config_value(interface, key): return list(line.split()) return [] -def get_dhcp6c_config_value(interface, key): - tmp = read_file(dhcp6c_config_file.format(interface)) - tmp = re.findall(r'\n?{}\s+(.*)'.format(key), tmp) - - out = [] - for item in tmp: - out.append(item.replace(';','')) - return out - +# add a classmethod to setup a temporaray PPPoE server for "proper" validation class PPPoEInterfaceTest(VyOSUnitTestSHIM.TestCase): def setUp(self): self._interfaces = ['pppoe10', 'pppoe20', 'pppoe30'] self._source_interface = 'eth0' def tearDown(self): + # Validate PPPoE client process + for interface in self._interfaces: + running = False + for proc in process_iter(): + if interface in proc.cmdline(): + running = True + break + self.assertTrue(running) + self.cli_delete(base_path) self.cli_commit() - def test_pppoe_client(self): + def test_01_pppoe_client(self): # Check if PPPoE dialer can be configured and runs for interface in self._interfaces: user = 'VyOS-user-' + interface @@ -71,8 +70,8 @@ class PPPoEInterfaceTest(VyOSUnitTestSHIM.TestCase): self.cli_commit() self.cli_set(base_path + [interface, 'source-interface', self._source_interface]) - # commit changes - self.cli_commit() + # commit changes + self.cli_commit() # verify configuration file(s) for interface in self._interfaces: @@ -88,17 +87,7 @@ class PPPoEInterfaceTest(VyOSUnitTestSHIM.TestCase): tmp = get_config_value(interface, 'ifname')[1] self.assertEqual(tmp, interface) - # Check if ppp process is running in the interface in question - running = False - for p in process_iter(): - if "pppd" in p.name(): - if interface in p.cmdline(): - running = True - - self.assertTrue(running) - - - def test_pppoe_clent_disabled_interface(self): + def test_02_pppoe_client_disabled_interface(self): # Check if PPPoE Client can be disabled for interface in self._interfaces: self.cli_set(base_path + [interface, 'authentication', 'user', 'vyos']) @@ -106,23 +95,45 @@ class PPPoEInterfaceTest(VyOSUnitTestSHIM.TestCase): self.cli_set(base_path + [interface, 'source-interface', self._source_interface]) self.cli_set(base_path + [interface, 'disable']) - self.cli_commit() + self.cli_commit() - # Validate PPPoE client process - running = False + # Validate PPPoE client process - must not run as interfaces are disabled for interface in self._interfaces: + running = False for proc in process_iter(): if interface in proc.cmdline(): running = True + break + self.assertFalse(running) + + # enable PPPoE interfaces + for interface in self._interfaces: + self.cli_delete(base_path + [interface, 'disable']) + + self.cli_commit() + - self.assertFalse(running) + def test_03_pppoe_authentication(self): + # When username or password is set - so must be the other + for interface in self._interfaces: + self.cli_set(base_path + [interface, 'authentication', 'user', 'vyos']) + self.cli_set(base_path + [interface, 'source-interface', self._source_interface]) + self.cli_set(base_path + [interface, 'ipv6', 'address', 'autoconf']) + # check validate() - if user is set, so must be the password + with self.assertRaises(ConfigSessionError): + self.cli_commit() + + self.cli_set(base_path + [interface, 'authentication', 'password', 'vyos']) + + self.cli_commit() - def test_pppoe_dhcpv6pd(self): + def test_04_pppoe_dhcpv6pd(self): # Check if PPPoE dialer can be configured with DHCPv6-PD address = '1' sla_id = '0' sla_len = '8' + for interface in self._interfaces: self.cli_set(base_path + [interface, 'authentication', 'user', 'vyos']) self.cli_set(base_path + [interface, 'authentication', 'password', 'vyos']) @@ -147,51 +158,8 @@ class PPPoEInterfaceTest(VyOSUnitTestSHIM.TestCase): self.assertEqual(tmp, 'vyos') tmp = get_config_value(interface, 'password')[1].replace('"', '') self.assertEqual(tmp, 'vyos') - - for param in ['+ipv6', 'ipv6cp-use-ipaddr']: - tmp = get_config_value(interface, param)[0] - self.assertEqual(tmp, param) - - # verify DHCPv6 prefix delegation - # will return: ['delegation', '::/56 infinity;'] - tmp = get_dhcp6c_config_value(interface, 'prefix')[1].split()[0] # mind the whitespace - self.assertEqual(tmp, '::/56') - tmp = get_dhcp6c_config_value(interface, 'prefix-interface')[0].split()[0] - self.assertEqual(tmp, self._source_interface) - tmp = get_dhcp6c_config_value(interface, 'ifid')[0] - self.assertEqual(tmp, address) - tmp = get_dhcp6c_config_value(interface, 'sla-id')[0] - self.assertEqual(tmp, sla_id) - tmp = get_dhcp6c_config_value(interface, 'sla-len')[0] - self.assertEqual(tmp, sla_len) - - # Check if ppp process is running in the interface in question - running = False - for p in process_iter(): - if "pppd" in p.name(): - running = True - self.assertTrue(running) - - # We can not check if wide-dhcpv6 process is running as it is started - # after the PPP interface gets a link to the ISP - but we can see if - # it would be started by the scripts - tmp = read_file(f'/etc/ppp/ipv6-up.d/1000-vyos-pppoe-{interface}') - tmp = re.findall(f'systemctl restart dhcp6c@{interface}.service', tmp) - self.assertTrue(tmp) - - def test_pppoe_authentication(self): - # When username or password is set - so must be the other - interface = 'pppoe0' - self.cli_set(base_path + [interface, 'authentication', 'user', 'vyos']) - self.cli_set(base_path + [interface, 'source-interface', self._source_interface]) - self.cli_set(base_path + [interface, 'ipv6', 'address', 'autoconf']) - - # check validate() - if user is set, so must be the password - with self.assertRaises(ConfigSessionError): - self.cli_commit() - - self.cli_set(base_path + [interface, 'authentication', 'password', 'vyos']) - self.cli_commit() + tmp = get_config_value(interface, '+ipv6 ipv6cp-use-ipaddr') + self.assertListEqual(tmp, ['+ipv6', 'ipv6cp-use-ipaddr']) if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/smoketest/scripts/cli/test_nat66.py b/smoketest/scripts/cli/test_nat66.py index dca92c97d..7721105e0 100755 --- a/smoketest/scripts/cli/test_nat66.py +++ b/smoketest/scripts/cli/test_nat66.py @@ -31,10 +31,13 @@ src_path = base_path + ['source'] dst_path = base_path + ['destination'] class TestNAT66(VyOSUnitTestSHIM.TestCase): - def setUp(self): + @classmethod + def setUpClass(cls): + super(cls, cls).setUpClass() + # ensure we can also run this test on a live system - so lets clean # out the current configuration :) - self.cli_delete(base_path) + cls.cli_delete(cls, base_path) def tearDown(self): self.cli_delete(base_path) @@ -183,4 +186,4 @@ class TestNAT66(VyOSUnitTestSHIM.TestCase): self.cli_commit() if __name__ == '__main__': - unittest.main(verbosity=2) + unittest.main(verbosity=2, failfast=True) diff --git a/smoketest/scripts/cli/test_policy.py b/smoketest/scripts/cli/test_policy.py index 66d3f3812..c2288a86a 100755 --- a/smoketest/scripts/cli/test_policy.py +++ b/smoketest/scripts/cli/test_policy.py @@ -1149,5 +1149,58 @@ class TestPolicy(VyOSUnitTestSHIM.TestCase): self.assertEqual(tmp, original) + # Test set table for fwmark + def test_fwmark_table_id(self): + path = base_path + ['local-route'] + + fwmk = '24' + rule = '101' + table = '154' + + self.cli_set(path + ['rule', rule, 'set', 'table', table]) + self.cli_set(path + ['rule', rule, 'fwmark', fwmk]) + + self.cli_commit() + + # Check generated configuration + + # Expected values + original = """ + 101: from all fwmark 0x18 lookup 154 + """ + tmp = cmd('ip rule show prio 101') + original = original.split() + tmp = tmp.split() + + self.assertEqual(tmp, original) + + # Test set table for sources with fwmark + def test_fwmark_sources_table_id(self): + path = base_path + ['local-route'] + + sources = ['203.0.113.11', '203.0.113.12'] + fwmk = '23' + rule = '100' + table = '150' + for src in sources: + self.cli_set(path + ['rule', rule, 'set', 'table', table]) + self.cli_set(path + ['rule', rule, 'source', src]) + self.cli_set(path + ['rule', rule, 'fwmark', fwmk]) + + self.cli_commit() + + # Check generated configuration + + # Expected values + original = """ + 100: from 203.0.113.11 fwmark 0x17 lookup 150 + 100: from 203.0.113.12 fwmark 0x17 lookup 150 + """ + tmp = cmd('ip rule show prio 100') + original = original.split() + tmp = tmp.split() + + self.assertEqual(tmp, original) + if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/smoketest/scripts/cli/test_protocols_bgp.py b/smoketest/scripts/cli/test_protocols_bgp.py index c3a2ffbf9..df9dc342b 100755 --- a/smoketest/scripts/cli/test_protocols_bgp.py +++ b/smoketest/scripts/cli/test_protocols_bgp.py @@ -78,6 +78,7 @@ neighbor_config = { 'cap_over' : '', 'ttl_security' : '5', 'local_as' : '300', + 'solo' : '', 'route_map_in' : route_map_in, 'route_map_out': route_map_out, 'no_send_comm_std' : '', @@ -173,6 +174,8 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase): self.assertIn(f' neighbor {peer} password {peer_config["password"]}', frrconfig) if 'remote_as' in peer_config: self.assertIn(f' neighbor {peer} remote-as {peer_config["remote_as"]}', frrconfig) + if 'solo' in peer_config: + self.assertIn(f' neighbor {peer} solo', frrconfig) if 'shutdown' in peer_config: self.assertIn(f' neighbor {peer} shutdown', frrconfig) if 'ttl_security' in peer_config: @@ -296,6 +299,8 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase): self.cli_set(base_path + ['neighbor', peer, 'strict-capability-match']) if 'shutdown' in peer_config: self.cli_set(base_path + ['neighbor', peer, 'shutdown']) + if 'solo' in peer_config: + self.cli_set(base_path + ['neighbor', peer, 'solo']) if 'ttl_security' in peer_config: self.cli_set(base_path + ['neighbor', peer, 'ttl-security', 'hops', peer_config["ttl_security"]]) if 'update_src' in peer_config: @@ -628,6 +633,9 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase): # templates and Jinja2 FRR template. table = '1000' + self.cli_set(base_path + ['local-as', ASN]) + # testing only one AFI is sufficient as it's generic code + for vrf in vrfs: vrf_base = ['vrf', 'name', vrf] self.cli_set(vrf_base + ['table', table]) @@ -636,15 +644,26 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase): self.cli_set(vrf_base + ['protocols', 'bgp', 'route-map', route_map_in]) table = str(int(table) + 1000) + # import VRF routes do main RIB + self.cli_set(base_path + ['address-family', 'ipv6-unicast', 'import', 'vrf', vrf]) + self.cli_commit() + # Verify FRR bgpd configuration + frrconfig = self.getFRRconfig(f'router bgp {ASN}') + 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) + # Verify FRR bgpd configuration - frrconfig = self.getFRRconfig(f'router bgp {ASN} vrf {vrf}') - self.assertIn(f'router bgp {ASN} vrf {vrf}', frrconfig) - self.assertIn(f' bgp router-id {router_id}', frrconfig) + frr_vrf_config = self.getFRRconfig(f'router bgp {ASN} vrf {vrf}') + self.assertIn(f'router bgp {ASN} vrf {vrf}', frr_vrf_config) + self.assertIn(f' bgp router-id {router_id}', frr_vrf_config) - # CCC: Currently this is not working as FRR() class does not support + # 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. # @@ -694,13 +713,27 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase): self.assertIn(f' neighbor {interface} activate', frrconfig) self.assertIn(f' exit-address-family', frrconfig) - def test_bgp_13_solo(self): + + def test_bgp_13_vpn(self): remote_asn = str(int(ASN) + 150) neighbor = '192.0.2.55' + vrf_name = 'red' + label = 'auto' + rd = f'{neighbor}:{ASN}' + rt_export = f'{neighbor}:1002 1.2.3.4:567' + rt_import = f'{neighbor}:1003 500:100' self.cli_set(base_path + ['local-as', ASN]) - self.cli_set(base_path + ['neighbor', neighbor, 'remote-as', remote_asn]) - self.cli_set(base_path + ['neighbor', neighbor, 'solo']) + # testing only one AFI is sufficient as it's generic code + for afi in ['ipv4-unicast', 'ipv6-unicast']: + self.cli_set(base_path + ['address-family', afi, 'export', 'vpn']) + self.cli_set(base_path + ['address-family', afi, 'import', 'vpn']) + self.cli_set(base_path + ['address-family', afi, 'label', 'vpn', 'export', label]) + self.cli_set(base_path + ['address-family', afi, 'rd', 'vpn', 'export', rd]) + self.cli_set(base_path + ['address-family', afi, 'route-map', 'vpn', 'export', route_map_out]) + self.cli_set(base_path + ['address-family', afi, 'route-map', 'vpn', 'import', route_map_in]) + self.cli_set(base_path + ['address-family', afi, 'route-target', 'vpn', 'export', rt_export]) + self.cli_set(base_path + ['address-family', afi, 'route-target', 'vpn', 'import', rt_import]) # commit changes self.cli_commit() @@ -708,7 +741,19 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase): # Verify FRR bgpd configuration frrconfig = self.getFRRconfig(f'router bgp {ASN}') self.assertIn(f'router bgp {ASN}', frrconfig) - self.assertIn(f' neighbor {neighbor} solo', frrconfig) + + for afi in ['ipv4', 'ipv6']: + afi_config = self.getFRRconfig(f' address-family {afi} unicast', endsection='exit-address-family', daemon='bgpd') + self.assertIn(f'address-family {afi} unicast', afi_config) + self.assertIn(f' export vpn', afi_config) + self.assertIn(f' import vpn', afi_config) + self.assertIn(f' label vpn export {label}', afi_config) + self.assertIn(f' rd vpn export {rd}', afi_config) + self.assertIn(f' route-map vpn export {route_map_out}', afi_config) + self.assertIn(f' route-map vpn import {route_map_in}', afi_config) + self.assertIn(f' rt vpn export {rt_export}', afi_config) + self.assertIn(f' rt vpn import {rt_import}', afi_config) + self.assertIn(f' exit-address-family', afi_config) if __name__ == '__main__': unittest.main(verbosity=2)
\ No newline at end of file diff --git a/smoketest/scripts/cli/test_protocols_ospf.py b/smoketest/scripts/cli/test_protocols_ospf.py index 59862ca3d..3f13eec80 100755 --- a/smoketest/scripts/cli/test_protocols_ospf.py +++ b/smoketest/scripts/cli/test_protocols_ospf.py @@ -20,6 +20,7 @@ import unittest from base_vyostest_shim import VyOSUnitTestSHIM +from vyos.configsession import ConfigSessionError from vyos.ifconfig import Section from vyos.util import process_named_running from vyos.util import cmd @@ -220,21 +221,23 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase): for protocol in redistribute: self.cli_set(base_path + ['redistribute', protocol, 'metric', metric]) self.cli_set(base_path + ['redistribute', protocol, 'route-map', route_map]) - if protocol not in ['kernel', 'static']: - self.cli_set(base_path + ['redistribute', protocol, 'metric-type', metric_type]) + self.cli_set(base_path + ['redistribute', protocol, 'metric-type', metric_type]) # commit changes self.cli_commit() # Verify FRR ospfd configuration frrconfig = self.getFRRconfig('router ospf') - self.assertIn(f'router ospf', frrconfig) - for protocol in redistribute: - if protocol in ['kernel', 'static']: - self.assertIn(f' redistribute {protocol} metric {metric} route-map {route_map}', frrconfig) - else: + try: + self.assertIn(f'router ospf', frrconfig) + for protocol in redistribute: self.assertIn(f' redistribute {protocol} metric {metric} metric-type {metric_type} route-map {route_map}', frrconfig) - + except: + log.debug(frrconfig) + log.debug(cmd('sudo dmesg')) + log.debug(cmd('sudo cat /var/log/messages')) + log.debug(cmd('vtysh -c "show run"')) + self.fail('Now we can hopefully see why OSPF fails!') def test_ospf_09_virtual_link(self): networks = ['10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16'] @@ -266,7 +269,7 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase): self.assertIn(f' network {network} area {area}', frrconfig) - def test_ospf_10_interface_configureation(self): + def test_ospf_10_interface_configuration(self): interfaces = Section.interfaces('ethernet') password = 'vyos1234' bandwidth = '10000' @@ -349,6 +352,30 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase): frrconfig = self.getFRRconfig(zebra_route_map) self.assertNotIn(zebra_route_map, frrconfig) + def test_ospf_13_interface_area(self): + area = '0' + interfaces = Section.interfaces('ethernet') + + self.cli_set(base_path + ['area', area, 'network', '10.0.0.0/8']) + for interface in interfaces: + self.cli_set(base_path + ['interface', interface, 'area', area]) + + # we can not have bot area network and interface area set + with self.assertRaises(ConfigSessionError): + self.cli_commit() + self.cli_delete(base_path + ['area', area, 'network']) + + self.cli_commit() + + # Verify FRR ospfd configuration + frrconfig = self.getFRRconfig('router ospf') + self.assertIn(f'router ospf', frrconfig) + + for interface in interfaces: + config = self.getFRRconfig(f'interface {interface}') + self.assertIn(f'interface {interface}', config) + self.assertIn(f' ip ospf area {area}', config) + if __name__ == '__main__': logging.basicConfig(stream=sys.stderr, level=logging.DEBUG) unittest.main(verbosity=2) diff --git a/smoketest/scripts/cli/test_service_ssh.py b/smoketest/scripts/cli/test_service_ssh.py index c76f709b1..ded4d8301 100755 --- a/smoketest/scripts/cli/test_service_ssh.py +++ b/smoketest/scripts/cli/test_service_ssh.py @@ -41,10 +41,13 @@ def get_config_value(key): return tmp class TestServiceSSH(VyOSUnitTestSHIM.TestCase): - def setUp(self): + @classmethod + def setUpClass(cls): + super(cls, cls).setUpClass() + # ensure we can also run this test on a live system - so lets clean # out the current configuration :) - self.cli_delete(base_path) + cls.cli_delete(cls, base_path) def tearDown(self): # delete testing SSH config diff --git a/smoketest/scripts/cli/test_system_conntrack.py b/smoketest/scripts/cli/test_system_conntrack.py index 21d626d2f..a2380981b 100755 --- a/smoketest/scripts/cli/test_system_conntrack.py +++ b/smoketest/scripts/cli/test_system_conntrack.py @@ -147,8 +147,8 @@ class TestSystemConntrack(VyOSUnitTestSHIM.TestCase): self.assertEqual(get_sysctl(f'{parameter}'), parameter_config['default_value']) - def test_conntrack_module_disable(self): - # Some features are disabled by onloading the kernel helper module(s) + def test_conntrack_module_enable(self): + # conntrack helper modules are disabled by default modules = { 'ftp' : { 'driver' : ['nf_nat_ftp', 'nf_conntrack_ftp'], @@ -176,38 +176,39 @@ class TestSystemConntrack(VyOSUnitTestSHIM.TestCase): }, } + # load modules for module in modules: - self.cli_set(base_path + ['modules', module, 'disable']) + self.cli_set(base_path + ['modules', module]) # commit changes self.cli_commit() - # verify modules are no longer loaded on the system + # verify modules are loaded on the system for module, module_options in modules.items(): if 'driver' in module_options: for driver in module_options['driver']: - self.assertFalse(os.path.isdir(f'/sys/module/{driver}')) + self.assertTrue(os.path.isdir(f'/sys/module/{driver}')) if 'iptables' in module_options: rules = cmd('sudo iptables-save -t raw') for ruleset in module_options['iptables']: - self.assertNotIn(ruleset, rules) + self.assertIn(ruleset, rules) - # reload modules + # unload modules for module in modules: - self.cli_delete(base_path + ['modules', module, 'disable']) + self.cli_delete(base_path + ['modules', module]) # commit changes self.cli_commit() - # verify modules are again loaded on the system + # verify modules are not loaded on the system for module, module_options in modules.items(): if 'driver' in module_options: for driver in module_options['driver']: - self.assertTrue(os.path.isdir(f'/sys/module/{driver}')) + self.assertFalse(os.path.isdir(f'/sys/module/{driver}')) if 'iptables' in module_options: rules = cmd('sudo iptables-save -t raw') for ruleset in module_options['iptables']: - self.assertIn(ruleset, rules) + self.assertNotIn(ruleset, rules) def test_conntrack_hash_size(self): hash_size = '65536' diff --git a/smoketest/scripts/cli/test_vpn_ipsec.py b/smoketest/scripts/cli/test_vpn_ipsec.py index a34387dc9..f33268083 100755 --- a/smoketest/scripts/cli/test_vpn_ipsec.py +++ b/smoketest/scripts/cli/test_vpn_ipsec.py @@ -182,8 +182,10 @@ class TestVPNIPsec(VyOSUnitTestSHIM.TestCase): swanctl_conf_lines = [ f'version = 2', f'auth = psk', + f'rekey_time = 28800s', # default value f'proposals = aes128-sha1-modp1024', f'esp_proposals = aes128-sha1-modp1024', + f'life_time = 3600s', # default value f'local_addrs = {local_address} # dhcp:no', f'remote_addrs = {peer_ip}', f'mode = tunnel', @@ -255,6 +257,8 @@ class TestVPNIPsec(VyOSUnitTestSHIM.TestCase): def test_04_dmvpn(self): tunnel_if = 'tun100' nhrp_secret = 'secret' + ike_lifetime = '3600' + esp_lifetime = '1800' # Tunnel self.cli_set(tunnel_path + [tunnel_if, 'address', '172.16.253.134/29']) @@ -272,7 +276,7 @@ class TestVPNIPsec(VyOSUnitTestSHIM.TestCase): # IKE/ESP Groups self.cli_set(base_path + ['esp-group', esp_group, 'compression', 'disable']) - self.cli_set(base_path + ['esp-group', esp_group, 'lifetime', '1800']) + self.cli_set(base_path + ['esp-group', esp_group, 'lifetime', esp_lifetime]) self.cli_set(base_path + ['esp-group', esp_group, 'mode', 'transport']) self.cli_set(base_path + ['esp-group', esp_group, 'pfs', 'dh-group2']) self.cli_set(base_path + ['esp-group', esp_group, 'proposal', '2', 'encryption', 'aes256']) @@ -282,7 +286,7 @@ class TestVPNIPsec(VyOSUnitTestSHIM.TestCase): self.cli_set(base_path + ['ike-group', ike_group, 'ikev2-reauth', 'no']) self.cli_set(base_path + ['ike-group', ike_group, 'key-exchange', 'ikev1']) - self.cli_set(base_path + ['ike-group', ike_group, 'lifetime', '3600']) + self.cli_set(base_path + ['ike-group', ike_group, 'lifetime', ike_lifetime]) self.cli_set(base_path + ['ike-group', ike_group, 'proposal', '2', 'dh-group', '2']) self.cli_set(base_path + ['ike-group', ike_group, 'proposal', '2', 'encryption', 'aes256']) self.cli_set(base_path + ['ike-group', ike_group, 'proposal', '2', 'hash', 'sha1']) @@ -300,7 +304,8 @@ class TestVPNIPsec(VyOSUnitTestSHIM.TestCase): swanctl_lines = [ f'proposals = aes128-sha1-modp1024,aes256-sha1-modp1024', f'version = 1', - f'rekey_time = 3600s', + f'life_time = {ike_lifetime}s', + f'rekey_time = {esp_lifetime}s', f'esp_proposals = aes128-sha1-modp1024,aes256-sha1-modp1024,3des-md5-modp1024', f'local_ts = dynamic[gre]', f'remote_ts = dynamic[gre]', diff --git a/src/conf_mode/conntrack.py b/src/conf_mode/conntrack.py index 4e6e39c0f..68877f794 100755 --- a/src/conf_mode/conntrack.py +++ b/src/conf_mode/conntrack.py @@ -97,7 +97,7 @@ def apply(conntrack): # Depending on the enable/disable state of the ALG (Application Layer Gateway) # modules we need to either insmod or rmmod the helpers. for module, module_config in module_map.items(): - if dict_search(f'modules.{module}.disable', conntrack) != None: + if dict_search(f'modules.{module}', conntrack) is None: if 'ko' in module_config: for mod in module_config['ko']: # Only remove the module if it's loaded @@ -105,8 +105,9 @@ def apply(conntrack): cmd(f'rmmod {mod}') if 'iptables' in module_config: for rule in module_config['iptables']: - print(f'iptables --delete {rule}') - cmd(f'iptables --delete {rule}') + # Only install iptables rule if it does not exist + tmp = run(f'iptables --check {rule}') + if tmp == 0: cmd(f'iptables --delete {rule}') else: if 'ko' in module_config: for mod in module_config['ko']: @@ -115,9 +116,7 @@ def apply(conntrack): for rule in module_config['iptables']: # Only install iptables rule if it does not exist tmp = run(f'iptables --check {rule}') - if tmp > 0: - cmd(f'iptables --insert {rule}') - + if tmp > 0: cmd(f'iptables --insert {rule}') if process_named_running('conntrackd'): # Reload conntrack-sync daemon to fetch new sysctl values diff --git a/src/conf_mode/containers.py b/src/conf_mode/containers.py index 21b47f42a..32320a4b2 100755 --- a/src/conf_mode/containers.py +++ b/src/conf_mode/containers.py @@ -23,8 +23,11 @@ from ipaddress import ip_network from vyos.config import Config from vyos.configdict import dict_merge from vyos.configdict import node_changed +from vyos.util import call from vyos.util import cmd -from vyos.util import popen +from vyos.util import run +from vyos.util import read_file +from vyos.util import write_file from vyos.template import render from vyos.template import is_ipv4 from vyos.template import is_ipv6 @@ -41,27 +44,7 @@ def _cmd(command): print(command) return cmd(command) -# Container management functions -def container_exists(name): - ''' - https://docs.podman.io/en/latest/_static/api.html#operation/ContainerExistsLibpod - Check if container exists. Response codes. - 204 - container exists - 404 - no such container - ''' - tmp = _cmd(f"curl --unix-socket /run/podman/podman.sock 'http://d/v3.0.0/libpod/containers/{name}/exists'") - # If container exists it return status code "0" - code can not be displayed - return (tmp == "") - -def container_status(name): - ''' - https://docs.podman.io/en/latest/_static/api.html#operation/ContainerInspectLibpod - ''' - tmp = _cmd(f"curl --unix-socket /run/podman/podman.sock 'http://d/v3.0.0/libpod/containers/{name}/json'") - data = json.loads(tmp) - return data['State']['Status'] - -def ctnr_network_exists(name): +def network_exists(name): # Check explicit name for network, returns True if network exists c = _cmd(f'podman network ls --quiet --filter name=^{name}$') return bool(c) @@ -79,11 +62,20 @@ def get_config(config=None): # We have gathered the dict representation of the CLI, but there are default # options which we need to update into the dictionary retrived. default_values = defaults(base) + # container base default values can not be merged here - remove and add them later + if 'name' in default_values: + del default_values['name'] container = dict_merge(default_values, container) + # Merge per-container default values + if 'name' in container: + default_values = defaults(base + ['name']) + for name in container['name']: + container['name'][name] = dict_merge(default_values, container['name'][name]) + # Delete container network, delete containers tmp = node_changed(conf, ['container', 'network']) - if tmp: container.update({'net_remove' : tmp}) + if tmp: container.update({'network_remove' : tmp}) tmp = node_changed(conf, ['container', 'name']) if tmp: container.update({'container_remove' : tmp}) @@ -102,7 +94,6 @@ def verify(container): if len(container_config['network']) > 1: raise ConfigError(f'Only one network can be specified for container "{name}"!') - # Check if the specified container network exists network_name = list(container_config['network'])[0] if network_name not in container['network']: @@ -125,8 +116,25 @@ def verify(container): # 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'Address "{address}" reserved for the container engine!') + raise ConfigError(f'IP address "{address}" can not be used for a container, '\ + 'reserved for the container engine!') + + if 'environment' in container_config: + for var, cfg in container_config['environment'].items(): + if 'value' not in cfg: + raise ConfigError(f'Environment variable {var} has no value assigned!') + if 'volume' in container_config: + for volume, volume_config in container_config['volume'].items(): + if 'source' not in volume_config: + raise ConfigError(f'Volume "{volume}" has no source path configured!') + + if 'destination' not in volume_config: + raise ConfigError(f'Volume "{volume}" has no destination path configured!') + + source = volume_config['source'] + if not os.path.exists(source): + raise ConfigError(f'Volume "{volume}" source path "{source}" does not exist!') # Container image is a mandatory option if 'image' not in container_config: @@ -142,9 +150,9 @@ def verify(container): # Add new network if 'network' in container: - v4_prefix = 0 - v6_prefix = 0 for network, network_config in container['network'].items(): + v4_prefix = 0 + v6_prefix = 0 # If ipv4-prefix not defined for user-defined network if 'prefix' not in network_config: raise ConfigError(f'prefix for network "{net}" must be defined!') @@ -160,8 +168,8 @@ def verify(container): # A network attached to a container can not be deleted - if {'net_remove', 'name'} <= set(container): - for network in container['net_remove']: + if {'network_remove', 'name'} <= set(container): + for network in container['network_remove']: for container, container_config in container['name'].items(): if 'network' in container_config and network in container_config['network']: raise ConfigError(f'Can not remove network "{network}", used by container "{container}"!') @@ -183,20 +191,19 @@ def apply(container): # Option "--force" allows to delete containers with any status if 'container_remove' in container: for name in container['container_remove']: - if container_status(name) == 'running': - _cmd(f'podman stop {name}') - _cmd(f'podman rm --force {name}') + call(f'podman stop {name}') + call(f'podman rm --force {name}') # Delete old networks if needed - if 'net_remove' in container: - for network in container['net_remove']: - _cmd(f'podman network rm {network}') + if 'network_remove' in container: + for network in container['network_remove']: + call(f'podman network rm --force {network}') # Add network if 'network' in container: for network, network_config in container['network'].items(): # Check if the network has already been created - if not ctnr_network_exists(network) and 'prefix' in network_config: + if not network_exists(network) and 'prefix' in network_config: tmp = f'podman network create {network}' # we can not use list comprehension here as the --ipv6 option # must immediately follow the specified subnet!!! @@ -206,56 +213,82 @@ def apply(container): tmp += ' --ipv6' _cmd(tmp) + # Disable masquerading and use traditional bridging so VyOS + # can control firewalling/NAT by the real VyOS CLI + cni_network_config = f'/etc/cni/net.d/{network}.conflist' + tmp = read_file(cni_network_config) + config = json.loads(tmp) + if 'plugins' in config: + for count in range(0, len(config['plugins'])): + if 'ipMasq' in config['plugins'][count]: + config['plugins'][count]['ipMasq'] = False + if 'hairpinMode' in config['plugins'][count]: + config['plugins'][count]['hairpinMode'] = False + + write_file(cni_network_config, json.dumps(config, indent=4)) + # Add container if 'name' in container: for name, container_config in container['name'].items(): - # Check if the container has already been created - if not container_exists(name): - image = container_config['image'] - # Currently the best way to run a command and immediately print stdout - print(os.system(f'podman pull {image}')) - - # Check/set environment options "-e foo=bar" - env_opt = '' - if 'environment' in container_config: - env_opt = '-e ' - env_opt += " -e ".join(f"{k}={v['value']}" for k, v in container_config['environment'].items()) - - # Publish ports - port = '' - if 'port' in container_config: - protocol = '' - for portmap in container_config['port']: - if 'protocol' in container_config['port'][portmap]: - protocol = container_config['port'][portmap]['protocol'] - protocol = f'/{protocol}' - else: - protocol = '/tcp' - sport = container_config['port'][portmap]['source'] - dport = container_config['port'][portmap]['destination'] - port += f' -p {sport}:{dport}{protocol}' - - # Bind volume - volume = '' - if 'volume' in container_config: - for vol in container_config['volume']: - svol = container_config['volume'][vol]['source'] - dvol = container_config['volume'][vol]['destination'] - volume += f' -v {svol}:{dvol}' - - if 'allow_host_networks' in container_config: - _cmd(f'podman run -dit --name {name} --net host {port} {volume} {env_opt} {image}') - else: - for network in container_config['network']: - ipparam = '' - if 'address' in container_config['network'][network]: - ipparam = '--ip ' + container_config['network'][network]['address'] - _cmd(f'podman run --name {name} -dit --net {network} {ipparam} {port} {volume} {env_opt} {image}') - - # Else container is already created. Just start it. - # It's needed after reboot. - elif container_status(name) != 'running': - _cmd(f'podman start {name}') + image = container_config['image'] + + if 'disable' in container_config: + # check if there is a container by that name running + tmp = _cmd('podman ps -a --format "{{.Names}}"') + if name in tmp: + _cmd(f'podman stop {name}') + _cmd(f'podman rm --force {name}') + continue + + memory = container_config['memory'] + restart = container_config['restart'] + + # Check if requested container image exists locally. If it does not, we + # pull it. print() is the best way to have a good response from the + # polling process to the user to display progress. If the image exists + # locally, a user can update it running `update container image <name>` + tmp = run(f'podman image exists {image}') + if tmp != 0: print(os.system(f'podman pull {image}')) + + # Check/set environment options "-e foo=bar" + env_opt = '' + if 'environment' in container_config: + for k, v in container_config['environment'].items(): + env_opt += f" -e \"{k}={v['value']}\"" + + # Publish ports + port = '' + if 'port' in container_config: + protocol = '' + for portmap in container_config['port']: + if 'protocol' in container_config['port'][portmap]: + protocol = container_config['port'][portmap]['protocol'] + protocol = f'/{protocol}' + else: + protocol = '/tcp' + sport = container_config['port'][portmap]['source'] + dport = container_config['port'][portmap]['destination'] + port += f' -p {sport}:{dport}{protocol}' + + # Bind volume + volume = '' + if 'volume' in container_config: + for vol, vol_config in container_config['volume'].items(): + svol = vol_config['source'] + dvol = vol_config['destination'] + volume += f' -v {svol}:{dvol}' + + container_base_cmd = f'podman run --detach --interactive --tty --replace ' \ + f'--memory {memory}m --memory-swap 0 --restart {restart} ' \ + f'--name {name} {port} {volume} {env_opt}' + if 'allow_host_networks' in container_config: + _cmd(f'{container_base_cmd} --net host {image}') + else: + for network in container_config['network']: + ipparam = '' + if 'address' in container_config['network'][network]: + ipparam = '--ip ' + container_config['network'][network]['address'] + _cmd(f'{container_base_cmd} --net {network} {ipparam} {image}') return None diff --git a/src/conf_mode/firewall_options.py b/src/conf_mode/firewall_options.py deleted file mode 100755 index 67bf5d0e2..000000000 --- a/src/conf_mode/firewall_options.py +++ /dev/null @@ -1,150 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright (C) 2018 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 sys -import os -import copy - -from vyos.config import Config -from vyos import ConfigError -from vyos.util import call - -from vyos import airbag -airbag.enable() - -default_config_data = { - 'intf_opts': [], - 'new_chain4': False, - 'new_chain6': False -} - -def get_config(config=None): - opts = copy.deepcopy(default_config_data) - if config: - conf = config - else: - conf = Config() - if not conf.exists('firewall options'): - # bail out early - return opts - else: - conf.set_level('firewall options') - - # Parse configuration of each individual instance - if conf.exists('interface'): - for intf in conf.list_nodes('interface'): - conf.set_level('firewall options interface {0}'.format(intf)) - config = { - 'intf': intf, - 'disabled': False, - 'mss4': '', - 'mss6': '' - } - - # Check if individual option is disabled - if conf.exists('disable'): - config['disabled'] = True - - # - # Get MSS value IPv4 - # - if conf.exists('adjust-mss'): - config['mss4'] = conf.return_value('adjust-mss') - - # We need a marker that a new iptables chain needs to be generated - if not opts['new_chain4']: - opts['new_chain4'] = True - - # - # Get MSS value IPv6 - # - if conf.exists('adjust-mss6'): - config['mss6'] = conf.return_value('adjust-mss6') - - # We need a marker that a new ip6tables chain needs to be generated - if not opts['new_chain6']: - opts['new_chain6'] = True - - # Append interface options to global list - opts['intf_opts'].append(config) - - return opts - -def verify(tcp): - # syntax verification is done via cli - return None - -def apply(tcp): - target = 'VYOS_FW_OPTIONS' - - # always cleanup iptables - call('iptables --table mangle --delete FORWARD --jump {} >&/dev/null'.format(target)) - call('iptables --table mangle --flush {} >&/dev/null'.format(target)) - call('iptables --table mangle --delete-chain {} >&/dev/null'.format(target)) - - # always cleanup ip6tables - call('ip6tables --table mangle --delete FORWARD --jump {} >&/dev/null'.format(target)) - call('ip6tables --table mangle --flush {} >&/dev/null'.format(target)) - call('ip6tables --table mangle --delete-chain {} >&/dev/null'.format(target)) - - # Setup new iptables rules - if tcp['new_chain4']: - call('iptables --table mangle --new-chain {} >&/dev/null'.format(target)) - call('iptables --table mangle --append FORWARD --jump {} >&/dev/null'.format(target)) - - for opts in tcp['intf_opts']: - intf = opts['intf'] - mss = opts['mss4'] - - # Check if this rule iis disabled - if opts['disabled']: - continue - - # adjust TCP MSS per interface - if mss: - call('iptables --table mangle --append {} --out-interface {} --protocol tcp ' - '--tcp-flags SYN,RST SYN --jump TCPMSS --set-mss {} >&/dev/null'.format(target, intf, mss)) - - # Setup new ip6tables rules - if tcp['new_chain6']: - call('ip6tables --table mangle --new-chain {} >&/dev/null'.format(target)) - call('ip6tables --table mangle --append FORWARD --jump {} >&/dev/null'.format(target)) - - for opts in tcp['intf_opts']: - intf = opts['intf'] - mss = opts['mss6'] - - # Check if this rule iis disabled - if opts['disabled']: - continue - - # adjust TCP MSS per interface - if mss: - call('ip6tables --table mangle --append {} --out-interface {} --protocol tcp ' - '--tcp-flags SYN,RST SYN --jump TCPMSS --set-mss {} >&/dev/null'.format(target, intf, mss)) - - return None - -if __name__ == '__main__': - - try: - c = get_config() - verify(c) - apply(c) - except ConfigError as e: - print(e) - sys.exit(1) diff --git a/src/conf_mode/interfaces-openvpn.py b/src/conf_mode/interfaces-openvpn.py index 74e29ed82..6be4e918b 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-2020 VyOS maintainers and contributors +# Copyright (C) 2019-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 @@ -273,6 +273,9 @@ def verify(openvpn): if openvpn['protocol'] == 'tcp-active': raise ConfigError('Protocol "tcp-active" is not valid in server mode') + if dict_search('authentication.username', openvpn) or dict_search('authentication.password', openvpn): + raise ConfigError('Cannot specify "authentication" in server mode') + if 'remote_port' in openvpn: raise ConfigError('Cannot specify "remote-port" in server mode') diff --git a/src/conf_mode/interfaces-pppoe.py b/src/conf_mode/interfaces-pppoe.py index 6c4c6c95b..584adc75e 100755 --- a/src/conf_mode/interfaces-pppoe.py +++ b/src/conf_mode/interfaces-pppoe.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2019-2020 VyOS maintainers and contributors +# Copyright (C) 2019-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 @@ -22,12 +22,16 @@ from netifaces import interfaces from vyos.config import Config from vyos.configdict import get_interface_dict +from vyos.configdict import leaf_node_changed from vyos.configverify import verify_authentication from vyos.configverify import verify_source_interface +from vyos.configverify import verify_interface_exists from vyos.configverify import verify_vrf from vyos.configverify import verify_mtu_ipv6 +from vyos.ifconfig import PPPoEIf from vyos.template import render from vyos.util import call +from vyos.util import is_systemd_service_running from vyos import ConfigError from vyos import airbag airbag.enable() @@ -44,6 +48,32 @@ def get_config(config=None): base = ['interfaces', 'pppoe'] pppoe = get_interface_dict(conf, base) + # We should only terminate the PPPoE session if critical parameters change. + # All parameters that can be changed on-the-fly (like interface description) + # should not lead to a reconnect! + tmp = leaf_node_changed(conf, ['access-concentrator']) + if tmp: pppoe.update({'shutdown_required': {}}) + + tmp = leaf_node_changed(conf, ['connect-on-demand']) + if tmp: pppoe.update({'shutdown_required': {}}) + + tmp = leaf_node_changed(conf, ['service-name']) + if tmp: pppoe.update({'shutdown_required': {}}) + + tmp = leaf_node_changed(conf, ['source-interface']) + if tmp: pppoe.update({'shutdown_required': {}}) + + tmp = leaf_node_changed(conf, ['vrf']) + # leaf_node_changed() returns a list, as VRF is a non-multi node, there + # will be only one list element + if tmp: pppoe.update({'vrf_old': tmp[0]}) + + tmp = leaf_node_changed(conf, ['authentication', 'user']) + if tmp: pppoe.update({'shutdown_required': {}}) + + tmp = leaf_node_changed(conf, ['authentication', 'password']) + if tmp: pppoe.update({'shutdown_required': {}}) + return pppoe def verify(pppoe): @@ -66,57 +96,42 @@ def generate(pppoe): # rendered into ifname = pppoe['ifname'] config_pppoe = f'/etc/ppp/peers/{ifname}' - script_pppoe_pre_up = f'/etc/ppp/ip-pre-up.d/1000-vyos-pppoe-{ifname}' - script_pppoe_ip_up = f'/etc/ppp/ip-up.d/1000-vyos-pppoe-{ifname}' - script_pppoe_ip_down = f'/etc/ppp/ip-down.d/1000-vyos-pppoe-{ifname}' - script_pppoe_ipv6_up = f'/etc/ppp/ipv6-up.d/1000-vyos-pppoe-{ifname}' - config_wide_dhcp6c = f'/run/dhcp6c/dhcp6c.{ifname}.conf' - - config_files = [config_pppoe, script_pppoe_pre_up, script_pppoe_ip_up, - script_pppoe_ip_down, script_pppoe_ipv6_up, config_wide_dhcp6c] if 'deleted' in pppoe or 'disable' in pppoe: - # stop DHCPv6-PD client - call(f'systemctl stop dhcp6c@{ifname}.service') - # Hang-up PPPoE connection - call(f'systemctl stop ppp@{ifname}.service') - - # Delete PPP configuration files - for file in config_files: - if os.path.exists(file): - os.unlink(file) + if os.path.exists(config_pppoe): + os.unlink(config_pppoe) return None # Create PPP configuration files - render(config_pppoe, 'pppoe/peer.tmpl', pppoe, permission=0o755) - - # Create script for ip-pre-up.d - render(script_pppoe_pre_up, 'pppoe/ip-pre-up.script.tmpl', pppoe, - permission=0o755) - # Create script for ip-up.d - render(script_pppoe_ip_up, 'pppoe/ip-up.script.tmpl', pppoe, - permission=0o755) - # Create script for ip-down.d - render(script_pppoe_ip_down, 'pppoe/ip-down.script.tmpl', pppoe, - permission=0o755) - # Create script for ipv6-up.d - render(script_pppoe_ipv6_up, 'pppoe/ipv6-up.script.tmpl', pppoe, - permission=0o755) - - if 'dhcpv6_options' in pppoe and 'pd' in pppoe['dhcpv6_options']: - # ipv6.tmpl relies on ifname - this should be made consitent in the - # future better then double key-ing the same value - render(config_wide_dhcp6c, 'dhcp-client/ipv6.tmpl', pppoe) + render(config_pppoe, 'pppoe/peer.tmpl', pppoe, permission=0o640) return None def apply(pppoe): + ifname = pppoe['ifname'] if 'deleted' in pppoe or 'disable' in pppoe: - call('systemctl stop ppp@{ifname}.service'.format(**pppoe)) + if os.path.isdir(f'/sys/class/net/{ifname}'): + p = PPPoEIf(ifname) + p.remove() + call(f'systemctl stop ppp@{ifname}.service') return None - call('systemctl restart ppp@{ifname}.service'.format(**pppoe)) + # reconnect should only be necessary when certain config options change, + # like ACS name, authentication, no-peer-dns, source-interface + if ((not is_systemd_service_running(f'ppp@{ifname}.service')) or + 'shutdown_required' in pppoe): + + # cleanup system (e.g. FRR routes first) + if os.path.isdir(f'/sys/class/net/{ifname}'): + p = PPPoEIf(ifname) + p.remove() + + call(f'systemctl restart ppp@{ifname}.service') + else: + if os.path.isdir(f'/sys/class/net/{ifname}'): + p = PPPoEIf(ifname) + p.update(pppoe) return None diff --git a/src/conf_mode/interfaces-wwan.py b/src/conf_mode/interfaces-wwan.py index 31c599145..faa5eb628 100755 --- a/src/conf_mode/interfaces-wwan.py +++ b/src/conf_mode/interfaces-wwan.py @@ -26,7 +26,6 @@ from vyos.configverify import verify_vrf from vyos.ifconfig import WWANIf from vyos.util import cmd from vyos.util import dict_search -from vyos.template import render from vyos import ConfigError from vyos import airbag airbag.enable() diff --git a/src/conf_mode/nat.py b/src/conf_mode/nat.py index dae958774..59939d0fb 100755 --- a/src/conf_mode/nat.py +++ b/src/conf_mode/nat.py @@ -139,12 +139,10 @@ def verify(nat): for rule, config in dict_search('source.rule', nat).items(): err_msg = f'Source NAT configuration error in rule {rule}:' if 'outbound_interface' not in config: - raise ConfigError(f'{err_msg}\n' \ - 'outbound-interface not specified') - else: - if config['outbound_interface'] not in 'any' and config['outbound_interface'] not in interfaces(): - print(f'WARNING: rule "{rule}" interface "{config["outbound_interface"]}" does not exist on this system') + raise ConfigError(f'{err_msg} outbound-interface not specified') + if config['outbound_interface'] not in 'any' and config['outbound_interface'] not in interfaces(): + print(f'WARNING: rule "{rule}" interface "{config["outbound_interface"]}" does not exist on this system') addr = dict_search('translation.address', config) if addr != None: diff --git a/src/conf_mode/nat66.py b/src/conf_mode/nat66.py index e2bd6417d..f8bc073bb 100755 --- a/src/conf_mode/nat66.py +++ b/src/conf_mode/nat66.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2020 VyOS maintainers and contributors +# 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 @@ -55,7 +55,7 @@ def get_config(config=None): conf = config else: conf = Config() - + base = ['nat66'] nat = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True) @@ -90,7 +90,7 @@ def get_config(config=None): # be done only once if not get_handler(condensed_json, 'PREROUTING', 'NAT_CONNTRACK'): nat['helper_functions'] = 'add' - + # Retrieve current table handler positions nat['pre_ct_ignore'] = get_handler(condensed_json, 'PREROUTING', 'VYATTA_CT_IGNORE') nat['pre_ct_conntrack'] = get_handler(condensed_json, 'PREROUTING', 'VYATTA_CT_PREROUTING_HOOK') @@ -109,21 +109,22 @@ def verify(nat): if 'helper_functions' in nat and nat['helper_functions'] != 'has': if not (nat['pre_ct_conntrack'] or nat['out_ct_conntrack']): raise Exception('could not determine nftable ruleset handlers') - + if dict_search('source.rule', nat): for rule, config in dict_search('source.rule', nat).items(): err_msg = f'Source NAT66 configuration error in rule {rule}:' if 'outbound_interface' not in config: - raise ConfigError(f'{err_msg}\n' \ - 'outbound-interface not specified') - else: - if config['outbound_interface'] not in interfaces(): - print(f'WARNING: rule "{rule}" interface "{config["outbound_interface"]}" does not exist on this system') + raise ConfigError(f'{err_msg} outbound-interface not specified') + + if config['outbound_interface'] not in interfaces(): + print(f'WARNING: rule "{rule}" interface "{config["outbound_interface"]}" does not exist on this system') addr = dict_search('translation.address', config) if addr != None: if addr != 'masquerade' and not is_ipv6(addr): raise ConfigError(f'Warning: IPv6 address {addr} is not a valid address') + else: + raise ConfigError(f'{err_msg} translation address not specified') prefix = dict_search('source.prefix', config) if prefix != None: @@ -145,7 +146,7 @@ def verify(nat): def generate(nat): render(iptables_nat_config, 'firewall/nftables-nat66.tmpl', nat, permission=0o755) - render(ndppd_config, 'proxy-ndp/ndppd.conf.tmpl', nat, permission=0o755) + render(ndppd_config, 'ndppd/ndppd.conf.tmpl', nat, permission=0o755) return None def apply(nat): diff --git a/src/conf_mode/policy-local-route.py b/src/conf_mode/policy-local-route.py index 013f22665..539189442 100755 --- a/src/conf_mode/policy-local-route.py +++ b/src/conf_mode/policy-local-route.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2020 VyOS maintainers and contributors +# 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 @@ -44,17 +44,26 @@ def get_config(config=None): if tmp: for rule in (tmp or []): src = leaf_node_changed(conf, ['policy', 'local-route', 'rule', rule, 'source']) + fwmk = leaf_node_changed(conf, ['policy', 'local-route', 'rule', rule, 'fwmark']) if src: dict = dict_merge({'rule_remove' : {rule : {'source' : src}}}, dict) pbr.update(dict) + if fwmk: + dict = dict_merge({'rule_remove' : {rule : {'fwmark' : fwmk}}}, dict) + pbr.update(dict) # delete policy local-route rule x source x.x.x.x + # delete policy local-route rule x fwmark x if 'rule' in pbr: for rule in pbr['rule']: src = leaf_node_changed(conf, ['policy', 'local-route', 'rule', rule, 'source']) + fwmk = leaf_node_changed(conf, ['policy', 'local-route', 'rule', rule, 'fwmark']) if src: dict = dict_merge({'rule_remove' : {rule : {'source' : src}}}, dict) pbr.update(dict) + if fwmk: + dict = dict_merge({'rule_remove' : {rule : {'fwmark' : fwmk}}}, dict) + pbr.update(dict) return pbr @@ -65,8 +74,8 @@ def verify(pbr): if 'rule' in pbr: for rule in pbr['rule']: - if 'source' not in pbr['rule'][rule]: - raise ConfigError('Source address required!') + if 'source' not in pbr['rule'][rule] and 'fwmark' not in pbr['rule'][rule]: + raise ConfigError('Source address or fwmark is required!') else: if 'set' not in pbr['rule'][rule] or 'table' not in pbr['rule'][rule]['set']: raise ConfigError('Table set is required!') @@ -86,16 +95,34 @@ def apply(pbr): # Delete old rule if needed if 'rule_remove' in pbr: for rule in pbr['rule_remove']: - for src in pbr['rule_remove'][rule]['source']: - call(f'ip rule del prio {rule} from {src}') + if 'source' in pbr['rule_remove'][rule]: + for src in pbr['rule_remove'][rule]['source']: + call(f'ip rule del prio {rule} from {src}') + if 'fwmark' in pbr['rule_remove'][rule]: + for fwmk in pbr['rule_remove'][rule]['fwmark']: + call(f'ip rule del prio {rule} from all fwmark {fwmk}') # Generate new config if 'rule' in pbr: for rule in pbr['rule']: table = pbr['rule'][rule]['set']['table'] - if pbr['rule'][rule]['source']: + # Only source in the rule + # set policy local-route rule 100 source '203.0.113.1' + if 'source' in pbr['rule'][rule] and not 'fwmark' in pbr['rule'][rule]: for src in pbr['rule'][rule]['source']: call(f'ip rule add prio {rule} from {src} lookup {table}') + # Only fwmark in the rule + # set policy local-route rule 101 fwmark '23' + if 'fwmark' in pbr['rule'][rule] and not 'source' in pbr['rule'][rule]: + fwmk = pbr['rule'][rule]['fwmark'] + call(f'ip rule add prio {rule} from all fwmark {fwmk} lookup {table}') + # Source and fwmark in the rule + # set policy local-route rule 100 source '203.0.113.1' + # set policy local-route rule 100 fwmark '23' + if 'source' in pbr['rule'][rule] and 'fwmark' in pbr['rule'][rule]: + fwmk = pbr['rule'][rule]['fwmark'] + for src in pbr['rule'][rule]['source']: + call(f'ip rule add prio {rule} from {src} fwmark {fwmk} lookup {table}') return None diff --git a/src/conf_mode/protocols_bgp.py b/src/conf_mode/protocols_bgp.py index 9ecfd07fe..7d05eed9f 100755 --- a/src/conf_mode/protocols_bgp.py +++ b/src/conf_mode/protocols_bgp.py @@ -23,6 +23,7 @@ from vyos.config import Config from vyos.configdict import dict_merge from vyos.configverify import verify_prefix_list from vyos.configverify import verify_route_map +from vyos.configverify import verify_vrf from vyos.template import is_ip from vyos.template import is_interface from vyos.template import render_to_string @@ -221,27 +222,47 @@ def verify(bgp): raise ConfigError(f'Peer-group "{peer_group}" requires remote-as to be set!') # Throw an error if the global administrative distance parameters aren't all filled out. - if dict_search('parameters.distance', bgp) == None: - pass - else: - if dict_search('parameters.distance.global', bgp): - for key in ['external', 'internal', 'local']: - if dict_search(f'parameters.distance.global.{key}', bgp) == None: - raise ConfigError('Missing mandatory configuration option for '\ - f'global administrative distance {key}!') - - # Throw an error if the address family specific administrative distance parameters aren't all filled out. - if dict_search('address_family', bgp) == None: - pass - else: - for address_family_name in dict_search('address_family', bgp): - if dict_search(f'address_family.{address_family_name}.distance', bgp) == None: - pass - else: + if dict_search('parameters.distance.global', bgp) != None: + for key in ['external', 'internal', 'local']: + if dict_search(f'parameters.distance.global.{key}', bgp) == None: + raise ConfigError('Missing mandatory configuration option for '\ + f'global administrative distance {key}!') + + # Address Family specific validation + if 'address_family' in bgp: + for afi, afi_config in bgp['address_family'].items(): + if 'distance' in afi_config: + # Throw an error if the address family specific administrative + # distance parameters aren't all filled out. for key in ['external', 'internal', 'local']: - if dict_search(f'address_family.{address_family_name}.distance.{key}', bgp) == None: + if key not in afi_config['distance']: raise ConfigError('Missing mandatory configuration option for '\ - f'{address_family_name} administrative distance {key}!') + f'{afi} administrative distance {key}!') + + if afi in ['ipv4_unicast', 'ipv6_unicast']: + if 'import' in afi_config and 'vrf' in afi_config['import']: + # Check if VRF exists + verify_vrf(afi_config['import']['vrf']) + + # FRR error: please unconfigure vpn to vrf commands before + # using import vrf commands + if 'vpn' in afi_config['import'] or dict_search('export.vpn', afi_config) != None: + raise ConfigError('Please unconfigure VPN to VRF commands before '\ + 'using "import vrf" commands!') + + # Verify that the export/import route-maps do exist + for export_import in ['export', 'import']: + tmp = dict_search(f'route_map.vpn.{export_import}', afi_config) + if tmp: verify_route_map(tmp, bgp) + + if afi in ['l2vpn_evpn'] and 'vrf' not in bgp: + # Some L2VPN EVPN AFI options are only supported under VRF + if 'vni' in afi_config: + for vni, vni_config in afi_config['vni'].items(): + if 'rd' in vni_config: + raise ConfigError('VNI route-distinguisher is only supported under EVPN VRF') + if 'route_target' in vni_config: + raise ConfigError('VNI route-target is only supported under EVPN VRF') return None diff --git a/src/conf_mode/protocols_isis.py b/src/conf_mode/protocols_isis.py index d4c82249b..4cf0312e9 100755 --- a/src/conf_mode/protocols_isis.py +++ b/src/conf_mode/protocols_isis.py @@ -113,9 +113,13 @@ def verify(isis): # Interface MTU must be >= configured lsp-mtu mtu = Interface(interface).get_mtu() area_mtu = isis['lsp_mtu'] - if mtu < int(area_mtu): - raise ConfigError(f'Interface {interface} has MTU {mtu}, minimum ' \ - f'area MTU is {area_mtu}!') + # Recommended maximum PDU size = interface MTU - 3 bytes + recom_area_mtu = mtu - 3 + if mtu < int(area_mtu) or int(area_mtu) > recom_area_mtu: + raise ConfigError(f'Interface {interface} has MTU {mtu}, ' \ + f'current area MTU is {area_mtu}! \n' \ + f'Recommended area lsp-mtu {recom_area_mtu} or less ' \ + '(calculated on MTU size).') if 'vrf' in isis: # If interface specific options are set, we must ensure that the diff --git a/src/conf_mode/protocols_ospf.py b/src/conf_mode/protocols_ospf.py index 78c1c82bd..06a29106d 100755 --- a/src/conf_mode/protocols_ospf.py +++ b/src/conf_mode/protocols_ospf.py @@ -149,14 +149,23 @@ def verify(ospf): if route_map_name: verify_route_map(route_map_name, ospf) if 'interface' in ospf: - for interface in ospf['interface']: + for interface, interface_config in ospf['interface'].items(): verify_interface_exists(interface) # One can not use dead-interval and hello-multiplier at the same # time. FRR will only activate the last option set via CLI. - if {'hello_multiplier', 'dead_interval'} <= set(ospf['interface'][interface]): + if {'hello_multiplier', 'dead_interval'} <= set(interface_config): raise ConfigError(f'Can not use hello-multiplier and dead-interval ' \ f'concurrently for {interface}!') + # One can not use the "network <prefix> area <id>" command and an + # per interface area assignment at the same time. FRR will error + # out using: "Please remove all network commands first." + if 'area' in ospf and 'area' in interface_config: + for area, area_config in ospf['area'].items(): + if 'network' in area_config: + raise ConfigError('Can not use OSPF interface area and area ' \ + 'network configuration at the same time!') + if 'vrf' in ospf: # If interface specific options are set, we must ensure that the # interface is bound to our requesting VRF. Due to the VyOS @@ -177,7 +186,7 @@ def generate(ospf): ospf['protocol'] = 'ospf' # required for frr/vrf.route-map.frr.tmpl ospf['frr_zebra_config'] = render_to_string('frr/vrf.route-map.frr.tmpl', ospf) - ospf['frr_ospfd_config'] = render_to_string('frr/ospf.frr.tmpl', ospf) + ospf['frr_ospfd_config'] = render_to_string('frr/ospfd.frr.tmpl', ospf) return None def apply(ospf): diff --git a/src/conf_mode/protocols_ospfv3.py b/src/conf_mode/protocols_ospfv3.py index fef0f509b..536ffa690 100755 --- a/src/conf_mode/protocols_ospfv3.py +++ b/src/conf_mode/protocols_ospfv3.py @@ -65,7 +65,7 @@ def verify(ospfv3): if 'ifmtu' in if_config: mtu = Interface(ifname).get_mtu() if int(if_config['ifmtu']) > int(mtu): - raise ConfigError(f'OSPFv3 ifmtu cannot go beyond physical MTU of "{mtu}"') + raise ConfigError(f'OSPFv3 ifmtu can not exceed physical MTU of "{mtu}"') return None @@ -74,7 +74,7 @@ def generate(ospfv3): ospfv3['new_frr_config'] = '' return None - ospfv3['new_frr_config'] = render_to_string('frr/ospfv3.frr.tmpl', ospfv3) + ospfv3['new_frr_config'] = render_to_string('frr/ospf6d.frr.tmpl', ospfv3) return None def apply(ospfv3): diff --git a/src/conf_mode/vpn_ipsec.py b/src/conf_mode/vpn_ipsec.py index d3065fc47..ff6090e22 100755 --- a/src/conf_mode/vpn_ipsec.py +++ b/src/conf_mode/vpn_ipsec.py @@ -286,20 +286,34 @@ def verify(ipsec): if 'pre_shared_secret' not in ra_conf['authentication']: raise ConfigError(f"Missing pre-shared-key on {name} remote-access config") + if 'client_mode' not in ra_conf['authentication']: + raise ConfigError('Client authentication method is required!') - if 'client_mode' in ra_conf['authentication']: - if ra_conf['authentication']['client_mode'] == 'eap-radius': - if 'radius' not in ipsec['remote_access'] or 'server' not in ipsec['remote_access']['radius'] or len(ipsec['remote_access']['radius']['server']) == 0: - raise ConfigError('RADIUS authentication requires at least one server') + if dict_search('authentication.client_mode', ra_conf) == 'eap-radius': + if dict_search('remote_access.radius.server', ipsec) == None: + raise ConfigError('RADIUS authentication requires at least one server') if 'pool' in ra_conf: + if {'dhcp', 'radius'} <= set(ra_conf['pool']): + raise ConfigError(f'Can not use both DHCP and RADIUS for address allocation '\ + f'at the same time for "{name}"!') + if 'dhcp' in ra_conf['pool'] and len(ra_conf['pool']) > 1: - raise ConfigError(f'Can not use both DHCP and a predefined address pool for "{name}"!') + raise ConfigError(f'Can not use DHCP and a predefined address pool for "{name}"!') + + if 'radius' in ra_conf['pool'] and len(ra_conf['pool']) > 1: + raise ConfigError(f'Can not use RADIUS and a predefined address pool for "{name}"!') for pool in ra_conf['pool']: if pool == 'dhcp': if dict_search('remote_access.dhcp.server', ipsec) == None: raise ConfigError('IPSec DHCP server is not configured!') + elif pool == 'radius': + if dict_search('remote_access.radius.server', ipsec) == None: + raise ConfigError('IPSec RADIUS server is not configured!') + + if dict_search('authentication.client_mode', ra_conf) != 'eap-radius': + raise ConfigError('RADIUS IP pool requires eap-radius client authentication!') elif 'pool' not in ipsec['remote_access'] or pool not in ipsec['remote_access']['pool']: raise ConfigError(f'Requested pool "{pool}" does not exist!') diff --git a/src/conf_mode/vrf.py b/src/conf_mode/vrf.py index c1cfc1dcb..919083ac4 100755 --- a/src/conf_mode/vrf.py +++ b/src/conf_mode/vrf.py @@ -24,7 +24,6 @@ from vyos.config import Config from vyos.configdict import node_changed 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 @@ -32,12 +31,9 @@ from vyos.util import get_interface_config from vyos.util import popen from vyos.util import run from vyos import ConfigError -from vyos import frr from vyos import airbag airbag.enable() -frr_daemon = 'zebra' - config_file = r'/etc/iproute2/rt_tables.d/vyos-vrf.conf' def list_rules(): @@ -131,7 +127,6 @@ def verify(vrf): def generate(vrf): render(config_file, 'vrf/vrf.conf.tmpl', vrf) - vrf['new_frr_config'] = render_to_string('frr/vrf.frr.tmpl', vrf) # Render nftables zones config vrf['nft_vrf_zones'] = NamedTemporaryFile().name render(vrf['nft_vrf_zones'], 'firewall/nftables-vrf-zones.tmpl', vrf) @@ -242,21 +237,6 @@ def apply(vrf): if tmp == 0: cmd('nft delete table inet vrf_zones') - # T3694: Somehow we hit a priority inversion here as we need to remove the - # VRF assigned VNI before we can remove a BGP bound VRF instance. Maybe - # move this to an individual helper script that set's up the VNI for the - # given VRF after any routing protocol. - # - # # add configuration to FRR - # frr_cfg = frr.FRRConfig() - # frr_cfg.load_configuration(frr_daemon) - # frr_cfg.modify_section(f'^vrf [a-zA-Z-]*$', '') - # frr_cfg.add_before(r'(interface .*|line vty)', vrf['new_frr_config']) - # frr_cfg.commit_configuration(frr_daemon) - # - # # Save configuration to /run/frr/config/frr.conf - # frr.save_configuration() - return None if __name__ == '__main__': diff --git a/src/conf_mode/vrf_vni.py b/src/conf_mode/vrf_vni.py new file mode 100755 index 000000000..87ee8f2d1 --- /dev/null +++ b/src/conf_mode/vrf_vni.py @@ -0,0 +1,76 @@ +#!/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() + + # This script only works with a passed VRF name + if len(argv) < 1: + raise NotImplementedError + vrf = argv[1] + + # "assemble" dict - easier here then use a full blown get_config_dict() + # on a single leafNode + vni = { 'vrf' : vrf } + tmp = conf.return_value(['vrf', 'name', vrf, 'vni']) + if tmp: vni.update({ 'vni' : tmp }) + + return vni + +def verify(vni): + return None + +def generate(vni): + vni['new_frr_config'] = render_to_string('frr/vrf-vni.frr.tmpl', vni) + return None + +def apply(vni): + # add configuration to FRR + frr_cfg = frr.FRRConfig() + frr_cfg.load_configuration(frr_daemon) + frr_cfg.modify_section(f'^vrf [a-zA-Z-]*$', '') + frr_cfg.add_before(r'(interface .*|line vty)', vni['new_frr_config']) + frr_cfg.commit_configuration(frr_daemon) + + # Save configuration to /run/frr/config/frr.conf + frr.save_configuration() + + 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/ipsec.d/vti-up-down b/src/etc/ipsec.d/vti-up-down index 281c9bf2b..011013a2e 100755 --- a/src/etc/ipsec.d/vti-up-down +++ b/src/etc/ipsec.d/vti-up-down @@ -55,7 +55,7 @@ if __name__ == '__main__': syslog(f'Interface {interface} not found') sys.exit(0) - vti_link_up = (vti_link['operstate'] == 'UP' if 'operstate' in vti_link else False) + vti_link_up = (vti_link['operstate'] != 'DOWN' if 'operstate' in vti_link else False) config = ConfigTreeQuery() vti_dict = config.get_config_dict(['interfaces', 'vti', interface], diff --git a/src/etc/ppp/ip-up.d/99-vyos-pppoe-callback b/src/etc/ppp/ip-up.d/99-vyos-pppoe-callback new file mode 100755 index 000000000..bb918a468 --- /dev/null +++ b/src/etc/ppp/ip-up.d/99-vyos-pppoe-callback @@ -0,0 +1,59 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 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/>. + +# This is a Python hook script which is invoked whenever a PPPoE session goes +# "ip-up". It will call into our vyos.ifconfig library and will then execute +# common tasks for the PPPoE interface. The reason we have to "hook" this is +# that we can not create a pppoeX interface in advance in linux and then connect +# pppd to this already existing interface. + +from sys import argv +from sys import exit + +from syslog import syslog +from syslog import openlog +from syslog import LOG_PID +from syslog import LOG_INFO + +from vyos.configquery import ConfigTreeQuery +from vyos.ifconfig import PPPoEIf +from vyos.util import read_file + +# When the ppp link comes up, this script is called with the following +# parameters +# $1 the interface name used by pppd (e.g. ppp3) +# $2 the tty device name +# $3 the tty device speed +# $4 the local IP address for the interface +# $5 the remote IP address +# $6 the parameter specified by the 'ipparam' option to pppd + +if (len(argv) < 7): + exit(1) + +interface = argv[6] +dialer_pid = read_file(f'/var/run/{interface}.pid') + +openlog(ident=f'pppd[{dialer_pid}]', facility=LOG_INFO) +syslog('executing ' + argv[0]) + +conf = ConfigTreeQuery() +pppoe = conf.get_config_dict(['interfaces', 'pppoe', argv[6]], + get_first_key=True, key_mangling=('-', '_')) +pppoe['ifname'] = argv[6] + +p = PPPoEIf(pppoe['ifname']) +p.update(pppoe) diff --git a/src/etc/sysctl.d/32-vyos-podman.conf b/src/etc/sysctl.d/32-vyos-podman.conf new file mode 100644 index 000000000..7068bf88d --- /dev/null +++ b/src/etc/sysctl.d/32-vyos-podman.conf @@ -0,0 +1,5 @@ +# Increase inotify watchers as per https://bugzilla.redhat.com/show_bug.cgi?id=1829596 +fs.inotify.max_queued_events = 1048576 +fs.inotify.max_user_instances = 1048576 +fs.inotify.max_user_watches = 1048576 + diff --git a/src/etc/udev/rules.d/90-vyos-serial.rules b/src/etc/udev/rules.d/90-vyos-serial.rules index 3f10f4924..872fd4fea 100644 --- a/src/etc/udev/rules.d/90-vyos-serial.rules +++ b/src/etc/udev/rules.d/90-vyos-serial.rules @@ -8,7 +8,7 @@ SUBSYSTEMS=="pci", IMPORT{builtin}="hwdb --subsystem=pci" SUBSYSTEMS=="usb", IMPORT{builtin}="usb_id", IMPORT{builtin}="hwdb --subsystem=usb" # /dev/serial/by-path/, /dev/serial/by-id/ for USB devices -KERNEL!="ttyUSB[0-9]*|ttyACM[0-9]*", GOTO="serial_end" +KERNEL!="ttyUSB[0-9]*", GOTO="serial_end" SUBSYSTEMS=="usb-serial", ENV{.ID_PORT}="$attr{port_number}" @@ -18,11 +18,11 @@ IMPORT{builtin}="path_id", IMPORT{builtin}="usb_id" # # - $env{ID_PATH} usually is a name like: "pci-0000:00:10.0-usb-0:2.3.3.4:1.0-port0" so we strip the "pci-*" # portion and only use the usb part -# - Transform the USB "speach" to the tree like structure so we start with "usb0" as root-complex 0. +# - Transform the USB "speech" to the tree like structure so we start with "usb0" as root-complex 0. # (tr -d -) does the replacement # - Replace the first group after ":" to represent the bus relation (sed -e 0,/:/s//b/) indicated by "b" # - Replace the next group after ":" to represent the port relation (sed -e 0,/:/s//p/) indicated by "p" -ENV{ID_PATH}=="?*", ENV{.ID_PORT}=="", PROGRAM="/bin/sh -c 'D=$env{ID_PATH}; echo ${D:17} | tr -d - | sed -e 0,/:/s//b/ | sed -e 0,/:/s//p/'", SYMLINK+="serial/by-bus/$result" -ENV{ID_PATH}=="?*", ENV{.ID_PORT}=="?*", PROGRAM="/bin/sh -c 'D=$env{ID_PATH}; echo ${D:17} | tr -d - | sed -e 0,/:/s//b/ | sed -e 0,/:/s//p/'", SYMLINK+="serial/by-bus/$result" +ENV{ID_PATH}=="?*", ENV{.ID_PORT}=="", PROGRAM="/bin/sh -c 'echo $env{ID_PATH:17} | tr -d - | sed -e 0,/:/s//b/ | sed -e 0,/:/s//p/'", SYMLINK+="serial/by-bus/$result" +ENV{ID_PATH}=="?*", ENV{.ID_PORT}=="?*", PROGRAM="/bin/sh -c 'echo $env{ID_PATH:17} | tr -d - | sed -e 0,/:/s//b/ | sed -e 0,/:/s//p/'", SYMLINK+="serial/by-bus/$result" LABEL="serial_end" diff --git a/src/etc/update-motd.d/99-reboot b/src/etc/update-motd.d/99-reboot new file mode 100755 index 000000000..718be1a7a --- /dev/null +++ b/src/etc/update-motd.d/99-reboot @@ -0,0 +1,7 @@ +#!/bin/vbash +source /opt/vyatta/etc/functions/script-template +if [ -f /run/systemd/shutdown/scheduled ]; then + echo + run show reboot +fi +exit diff --git a/src/migration-scripts/conntrack/2-to-3 b/src/migration-scripts/conntrack/2-to-3 new file mode 100755 index 000000000..8a8b43279 --- /dev/null +++ b/src/migration-scripts/conntrack/2-to-3 @@ -0,0 +1,37 @@ +#!/usr/bin/env python3 + +# Conntrack syntax version 3 +# Enables all conntrack modules (previous default behaviour) and omits manually disabled modules. + +import sys + +from vyos.configtree import ConfigTree +from vyos.version import get_version + +if len(sys.argv) < 1: + print('Must specify file name!') + sys.exit(1) + +filename = sys.argv[1] + +with open(filename, 'r') as f: + config = ConfigTree(f.read()) + +module_path = ['system', 'conntrack', 'modules'] + +# Go over all conntrack modules available as of v1.3.0. +for module in ['ftp', 'h323', 'nfs', 'pptp', 'sip', 'sqlnet', 'tftp']: + # 'disable' is being phased out. + if config.exists(module_path + [module, 'disable']): + config.delete(module_path + [module]) + # If it wasn't manually 'disable'd, it was enabled by default. + else: + config.set(module_path + [module]) + +try: + if config.exists(module_path): + with open(filename, 'w') as f: + f.write(config.to_string()) +except OSError as e: + print(f'Failed to save the modified config: {e}') + sys.exit(1) diff --git a/src/migration-scripts/firewall/5-to-6 b/src/migration-scripts/firewall/5-to-6 new file mode 100755 index 000000000..ccb86830a --- /dev/null +++ b/src/migration-scripts/firewall/5-to-6 @@ -0,0 +1,63 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 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/>. + +# T3090: migrate "firewall options interface <name> adjust-mss" to the +# individual interface. + +from sys import argv +from sys import exit + +from vyos.configtree import ConfigTree +from vyos.ifconfig import Section + +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() + +base = ['firewall', 'options', 'interface'] +config = ConfigTree(config_file) + +if not config.exists(base): + # Nothing to do + exit(0) + +for interface in config.list_nodes(base): + if config.exists(base + [interface, 'disable']): + continue + + if config.exists(base + [interface, 'adjust-mss']): + section = Section.section(interface) + tmp = config.return_value(base + [interface, 'adjust-mss']) + config.set(['interfaces', section, interface, 'ip', 'adjust-mss'], value=tmp) + + if config.exists(base + [interface, 'adjust-mss6']): + section = Section.section(interface) + tmp = config.return_value(base + [interface, 'adjust-mss6']) + config.set(['interfaces', section, interface, 'ipv6', 'adjust-mss'], value=tmp) + +config.delete(['firewall', 'options']) + +try: + with open(file_name, 'w') as f: + f.write(config.to_string()) +except OSError as e: + print("Failed to save the modified config: {}".format(e)) + exit(1) diff --git a/src/op_mode/containers_op.py b/src/op_mode/containers_op.py index 1e3fc3a8f..bc317029c 100755 --- a/src/op_mode/containers_op.py +++ b/src/op_mode/containers_op.py @@ -15,10 +15,10 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. import argparse -from vyos.configquery import query_context, ConfigQueryError -from vyos.util import cmd -config, op = query_context() +from getpass import getuser +from vyos.configquery import ConfigTreeQuery +from vyos.util import cmd parser = argparse.ArgumentParser() parser.add_argument("-a", "--all", action="store_true", help="Show all containers") @@ -26,34 +26,53 @@ parser.add_argument("-i", "--image", action="store_true", help="Show container i parser.add_argument("-n", "--networks", action="store_true", help="Show container images") parser.add_argument("-p", "--pull", action="store", help="Pull image for container") parser.add_argument("-d", "--remove", action="store", help="Delete container image") +parser.add_argument("-u", "--update", action="store", help="Update given container image") -if not config.exists(['container']): +config = ConfigTreeQuery() +base = ['container'] +if not config.exists(base): print('Containers not configured') exit(0) +if getuser() != 'root': + raise OSError('This functions needs to be run as root to return correct results!') + if __name__ == '__main__': args = parser.parse_args() if args.all: print(cmd('podman ps --all')) - exit(0) - if args.image: + + elif args.image: print(cmd('podman image ls')) - exit(0) - if args.networks: + + elif args.networks: print(cmd('podman network ls')) - exit(0) - if args.pull: + + elif args.pull: image = args.pull try: - print(cmd(f'sudo podman image pull {image}')) + print(cmd(f'podman image pull {image}')) except: print(f'Can\'t find or download image "{image}"') - exit(0) - if args.remove: + + elif args.remove: image = args.remove try: - print(cmd(f'sudo podman image rm {image}')) + print(cmd(f'podman image rm {image}')) except: print(f'Can\'t delete image "{image}"') - exit(0) + + elif args.update: + tmp = config.get_config_dict(base + ['name', args.update], + key_mangling=('-', '_'), get_first_key=True) + try: + image = tmp['image'] + print(cmd(f'podman image pull {image}')) + except: + print(f'Can\'t find or download image "{image}"') + else: + parser.print_help() + exit(1) + + exit(0) diff --git a/src/op_mode/dns_forwarding_statistics.py b/src/op_mode/dns_forwarding_statistics.py index 1fb61d263..d79b6c024 100755 --- a/src/op_mode/dns_forwarding_statistics.py +++ b/src/op_mode/dns_forwarding_statistics.py @@ -11,7 +11,7 @@ PDNS_CMD='/usr/bin/rec_control --socket-dir=/run/powerdns' OUT_TMPL_SRC = """ DNS forwarding statistics: -Cache entries: {{ cache_entries -}} +Cache entries: {{ cache_entries }} Cache size: {{ cache_size }} kbytes """ diff --git a/src/op_mode/ikev2_profile_generator.py b/src/op_mode/ikev2_profile_generator.py index d45525431..990b06c12 100755 --- a/src/op_mode/ikev2_profile_generator.py +++ b/src/op_mode/ikev2_profile_generator.py @@ -21,7 +21,7 @@ from sys import exit from socket import getfqdn from cryptography.x509.oid import NameOID -from vyos.config import Config +from vyos.configquery import ConfigTreeQuery from vyos.pki import load_certificate from vyos.template import render_to_string from vyos.util import ask_input @@ -117,7 +117,7 @@ args = parser.parse_args() ipsec_base = ['vpn', 'ipsec'] config_base = ipsec_base + ['remote-access', 'connection'] pki_base = ['pki'] -conf = Config() +conf = ConfigTreeQuery() if not conf.exists(config_base): exit('IPSec remote-access is not configured!') @@ -153,7 +153,7 @@ cert = load_certificate(pki['certificate'][cert_name]['certificate']) data['ca_cn'] = ca_cert.subject.get_attributes_for_oid(NameOID.COMMON_NAME)[0].value data['cert_cn'] = cert.subject.get_attributes_for_oid(NameOID.COMMON_NAME)[0].value -data['ca_cert'] = conf.return_value(pki_base + ['ca', ca_name, 'certificate']) +data['ca_cert'] = conf.value(pki_base + ['ca', ca_name, 'certificate']) esp_proposals = conf.get_config_dict(ipsec_base + ['esp-group', data['esp_group'], 'proposal'], key_mangling=('-', '_'), get_first_key=True) diff --git a/src/op_mode/pki.py b/src/op_mode/pki.py index 297270cf1..36891d080 100755 --- a/src/op_mode/pki.py +++ b/src/op_mode/pki.py @@ -24,7 +24,7 @@ import tabulate from cryptography import x509 from cryptography.x509.oid import ExtendedKeyUsageOID -from vyos.config import Config +from vyos.configquery import ConfigTreeQuery from vyos.configdict import dict_merge from vyos.pki import encode_certificate, encode_public_key, encode_private_key, encode_dh_parameters from vyos.pki import create_certificate, create_certificate_request, create_certificate_revocation_list @@ -41,10 +41,10 @@ CERT_REQ_END = '-----END CERTIFICATE REQUEST-----' auth_dir = '/config/auth' # Helper Functions - +conf = ConfigTreeQuery() def get_default_values(): # Fetch default x509 values - conf = Config() + base = ['pki', 'x509', 'default'] x509_defaults = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True, no_tag_node_value_mangle=True) @@ -53,9 +53,7 @@ def get_default_values(): def get_config_ca_certificate(name=None): # Fetch ca certificates from config - conf = Config() base = ['pki', 'ca'] - if not conf.exists(base): return False @@ -69,9 +67,7 @@ def get_config_ca_certificate(name=None): def get_config_certificate(name=None): # Get certificates from config - conf = Config() base = ['pki', 'certificate'] - if not conf.exists(base): return False @@ -100,7 +96,6 @@ def get_certificate_ca(cert, ca_certs): def get_config_revoked_certificates(): # Fetch revoked certificates from config - conf = Config() ca_base = ['pki', 'ca'] cert_base = ['pki', 'certificate'] @@ -464,7 +459,7 @@ def generate_certificate_sign(name, ca_name, install=False, file=False): if not cert_req: print("Invalid certificate request") return None - + cert = generate_certificate(cert_req, ca_cert, ca_private_key, is_ca=False) passphrase = ask_passphrase() @@ -813,7 +808,7 @@ if __name__ == '__main__': elif args.self_sign: generate_certificate_selfsign(args.certificate, install=args.install, file=args.file) else: - generate_certificate_request(name=args.certificate, install=args.install) + generate_certificate_request(name=args.certificate, install=args.install, file=args.file) elif args.crl: generate_certificate_revocation_list(args.crl, install=args.install, file=args.file) elif args.ssh: diff --git a/src/op_mode/restart_frr.py b/src/op_mode/restart_frr.py index d1b66b33f..0b2322478 100755 --- a/src/op_mode/restart_frr.py +++ b/src/op_mode/restart_frr.py @@ -155,7 +155,7 @@ def _check_args_daemon(daemons): # define program arguments cmd_args_parser = argparse.ArgumentParser(description='restart frr daemons') cmd_args_parser.add_argument('--action', choices=['restart'], required=True, help='action to frr daemons') -cmd_args_parser.add_argument('--daemon', choices=['bfdd', 'bgpd', 'ospfd', 'ospf6d', 'ripd', 'ripngd', 'staticd', 'zebra'], required=False, nargs='*', help='select single or multiple daemons') +cmd_args_parser.add_argument('--daemon', choices=['bfdd', 'bgpd', 'ospfd', 'ospf6d', 'isisd', 'ripd', 'ripngd', 'staticd', 'zebra'], required=False, nargs='*', help='select single or multiple daemons') # parse arguments cmd_args = cmd_args_parser.parse_args() diff --git a/src/op_mode/show_interfaces.py b/src/op_mode/show_interfaces.py index 20d5d9e17..241fba4f4 100755 --- a/src/op_mode/show_interfaces.py +++ b/src/op_mode/show_interfaces.py @@ -120,10 +120,6 @@ def split_text(text, used=0): yield line[1:] -def get_vrrp_intf(): - return [intf for intf in Section.interfaces() if intf.is_vrrp()] - - def get_counter_val(clear, now): """ attempt to correct a counter if it wrapped, copied from perl diff --git a/src/op_mode/show_ipsec_sa.py b/src/op_mode/show_ipsec_sa.py index e491267fd..c964caaeb 100755 --- a/src/op_mode/show_ipsec_sa.py +++ b/src/op_mode/show_ipsec_sa.py @@ -23,6 +23,12 @@ import hurry.filesize import vyos.util +def convert(text): + return int(text) if text.isdigit() else text.lower() + +def alphanum_key(key): + return [convert(c) for c in re.split('([0-9]+)', str(key))] + def format_output(conns, sas): sa_data = [] @@ -111,7 +117,7 @@ if __name__ == '__main__': headers = ["Connection", "State", "Uptime", "Bytes In/Out", "Packets In/Out", "Remote address", "Remote ID", "Proposal"] sa_data = format_output(conns, sas) - sa_data = sorted(sa_data, key=lambda peer: peer[0]) + sa_data = sorted(sa_data, key=alphanum_key) output = tabulate.tabulate(sa_data, headers) print(output) except PermissionError: diff --git a/src/op_mode/show_nat_rules.py b/src/op_mode/show_nat_rules.py index 0f40ecabe..4a059c848 100755 --- a/src/op_mode/show_nat_rules.py +++ b/src/op_mode/show_nat_rules.py @@ -67,46 +67,54 @@ if args.source or args.destination: continue interface = dict_search('match.right', data['expr'][0]) srcdest = '' - for i in [1, 2]: - srcdest_json = dict_search('match.right', data['expr'][i]) - if not srcdest_json: - continue - - if isinstance(srcdest_json,str): - srcdest += srcdest_json + ' ' - elif 'prefix' in srcdest_json: - addr_tmp = dict_search('match.right.prefix.addr', data['expr'][i]) - len_tmp = dict_search('match.right.prefix.len', data['expr'][i]) - if addr_tmp and len_tmp: - srcdest = addr_tmp + '/' + str(len_tmp) + ' ' - elif 'set' in srcdest_json: - if isinstance(srcdest_json['set'][0],str): - srcdest += 'port ' + str(srcdest_json['set'][0]) + ' ' - else: - port_range = srcdest_json['set'][0]['range'] - srcdest += 'port ' + str(port_range[0]) + '-' + str(port_range[1]) + ' ' - + srcdests = [] tran_addr = '' - tran_addr_json = dict_search('snat.addr' if args.source else 'dnat.addr', data['expr'][3]) - if tran_addr_json: - if isinstance(tran_addr_json,str): - tran_addr = tran_addr_json - elif 'prefix' in tran_addr_json: - addr_tmp = dict_search('snat.addr.prefix.addr' if args.source else 'dnat.addr.prefix.addr', data['expr'][3]) - len_tmp = dict_search('snat.addr.prefix.len' if args.source else 'dnat.addr.prefix.len', data['expr'][3]) - if addr_tmp and len_tmp: - tran_addr = addr_tmp + '/' + str(len_tmp) - else: - if 'masquerade' in data['expr'][3]: - tran_addr = 'masquerade' - elif 'log' in data['expr'][3]: - continue - - tran_port = dict_search('snat.port' if args.source else 'dnat.port', data['expr'][3]) - if tran_port: - tran_addr += ' port ' + str(tran_port) + for i in range(1,len(data['expr']) + 1): + srcdest_json = dict_search('match.right', data['expr'][i]) + if srcdest_json: + if isinstance(srcdest_json,str): + if srcdest != '': + srcdests.append(srcdest) + srcdest = '' + srcdest = srcdest_json + ' ' + elif 'prefix' in srcdest_json: + addr_tmp = dict_search('match.right.prefix.addr', data['expr'][i]) + len_tmp = dict_search('match.right.prefix.len', data['expr'][i]) + if addr_tmp and len_tmp: + srcdest = addr_tmp + '/' + str(len_tmp) + ' ' + elif 'set' in srcdest_json: + if isinstance(srcdest_json['set'][0],int): + srcdest += 'port ' + str(srcdest_json['set'][0]) + ' ' + else: + port_range = srcdest_json['set'][0]['range'] + srcdest += 'port ' + str(port_range[0]) + '-' + str(port_range[1]) + ' ' + + tran_addr_json = dict_search('snat' if args.source else 'dnat', data['expr'][i]) + if tran_addr_json: + if isinstance(tran_addr_json['addr'],str): + tran_addr += tran_addr_json['addr'] + ' ' + elif 'prefix' in tran_addr_json['addr']: + addr_tmp = dict_search('snat.addr.prefix.addr' if args.source else 'dnat.addr.prefix.addr', data['expr'][3]) + len_tmp = dict_search('snat.addr.prefix.len' if args.source else 'dnat.addr.prefix.len', data['expr'][3]) + if addr_tmp and len_tmp: + tran_addr += addr_tmp + '/' + str(len_tmp) + ' ' + + if isinstance(tran_addr_json['port'],int): + tran_addr += 'port ' + tran_addr_json['port'] + + else: + if 'masquerade' in data['expr'][i]: + tran_addr = 'masquerade' + elif 'log' in data['expr'][i]: + continue - print(format_nat_rule.format(rule, srcdest, tran_addr, interface)) + if srcdest != '': + srcdests.append(srcdest) + srcdest = '' + print(format_nat_rule.format(rule, srcdests[0], tran_addr, interface)) + + for i in range(1, list(srcdest)): + print(format_nat_rule.format(' ', srcdests[i], ' ', ' ')) exit(0) else: diff --git a/src/op_mode/show_system_integrity.py b/src/op_mode/show_system_integrity.py deleted file mode 100755 index c34d41e80..000000000 --- a/src/op_mode/show_system_integrity.py +++ /dev/null @@ -1,70 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright (C) 2020 VyOS maintainers and contributors -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2 or later as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. -# -# - -import sys -import os -import re -import json -from datetime import datetime, timedelta - -version_file = r'/usr/share/vyos/version.json' - - -def _get_sys_build_version(): - if not os.path.exists(version_file): - return None - buf = open(version_file, 'r').read() - j = json.loads(buf) - if not 'built_on' in j: - return None - return datetime.strptime(j['built_on'], '%a %d %b %Y %H:%M %Z') - - -def _check_pkgs(build_stamp): - pkg_diffs = { - 'buildtime': str(build_stamp), - 'pkg': {} - } - - pkg_info = os.listdir('/var/lib/dpkg/info/') - for file in pkg_info: - if re.search('\.list$', file): - fts = os.stat('/var/lib/dpkg/info/' + file).st_mtime - dt_str = (datetime.utcfromtimestamp( - fts).strftime('%Y-%m-%d %H:%M:%S')) - fdt = datetime.strptime(dt_str, '%Y-%m-%d %H:%M:%S') - if fdt > build_stamp: - pkg_diffs['pkg'].update( - {str(re.sub('\.list', '', file)): str(fdt)}) - - if len(pkg_diffs['pkg']) != 0: - return pkg_diffs - else: - return None - - -if __name__ == '__main__': - built_date = _get_sys_build_version() - if not built_date: - sys.exit(1) - pkgs = _check_pkgs(built_date) - if pkgs: - print ( - "The following packages don\'t fit the image creation time\nbuild time:\t" + pkgs['buildtime']) - for k, v in pkgs['pkg'].items(): - print ("installed: " + v + '\t' + k) diff --git a/src/op_mode/wireguard_client.py b/src/op_mode/wireguard_client.py index 7661254da..76c1ff7d1 100755 --- a/src/op_mode/wireguard_client.py +++ b/src/op_mode/wireguard_client.py @@ -39,10 +39,11 @@ To enable this configuration on a VyOS router you can use the following commands set interfaces wireguard {{ interface }} peer {{ name }} allowed-ips '{{ addr }}' {% endfor %} set interfaces wireguard {{ interface }} peer {{ name }} public-key '{{ pubkey }}' + +=== RoadWarrior (client) configuration === """ client_config = """ -=== RoadWarrior (client) configuration === [Interface] PrivateKey = {{ privkey }} diff --git a/src/systemd/opennhrp.service b/src/systemd/opennhrp.service index 70235f89d..c9a44de29 100644 --- a/src/systemd/opennhrp.service +++ b/src/systemd/opennhrp.service @@ -6,8 +6,8 @@ StartLimitIntervalSec=0 [Service] Type=forking -ExecStart=/usr/sbin/opennhrp -d -v -a /run/opennhrp.socket -c /run/opennhrp/opennhrp.conf -s /etc/opennhrp/opennhrp-script.py -p /run/opennhrp.pid +ExecStart=/usr/sbin/opennhrp -d -v -a /run/opennhrp.socket -c /run/opennhrp/opennhrp.conf -s /etc/opennhrp/opennhrp-script.py -p /run/opennhrp/opennhrp.pid ExecReload=/usr/bin/kill -HUP $MAINPID -PIDFile=/run/opennhrp.pid +PIDFile=/run/opennhrp/opennhrp.pid Restart=on-failure RestartSec=20 diff --git a/src/validators/bgp-large-community-list b/src/validators/bgp-large-community-list new file mode 100755 index 000000000..c07268e81 --- /dev/null +++ b/src/validators/bgp-large-community-list @@ -0,0 +1,36 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 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/>. + +import re +import sys + +from vyos.template import is_ipv4 + +pattern = '(.*):(.*):(.*)' + +if __name__ == '__main__': + if len(sys.argv) != 2: + sys.exit(1) + + value = sys.argv[1].split(':') + if not len(value) == 3: + sys.exit(1) + + if not (re.match(pattern, sys.argv[1]) and + (is_ipv4(value[0]) or value[0].isdigit()) and value[1].isdigit()): + sys.exit(1) + + sys.exit(0) diff --git a/src/validators/bgp-route-target b/src/validators/bgp-route-target new file mode 100755 index 000000000..e7e4d403f --- /dev/null +++ b/src/validators/bgp-route-target @@ -0,0 +1,51 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 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 argparse import ArgumentParser +from vyos.template import is_ipv4 + +parser = ArgumentParser() +group = parser.add_mutually_exclusive_group() +group.add_argument('--single', action='store', help='Validate and allow only one route-target') +group.add_argument('--multi', action='store', help='Validate multiple, whitespace separated route-targets') +args = parser.parse_args() + +def is_valid_rt(rt): + # every route target needs to have a colon and must consists of two parts + value = rt.split(':') + if len(value) != 2: + return False + # A route target must either be only numbers, or the first part must be an + # IPv4 address + if (is_ipv4(value[0]) or value[0].isdigit()) and value[1].isdigit(): + return True + return False + +if __name__ == '__main__': + if args.single: + if not is_valid_rt(args.single): + exit(1) + + elif args.multi: + for rt in args.multi.split(' '): + if not is_valid_rt(rt): + exit(1) + + else: + parser.print_help() + exit(1) + + exit(0) |