summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--data/op-mode-standardized.json2
-rw-r--r--interface-definitions/container.xml.in8
-rw-r--r--op-mode-definitions/include/vni-tagnode-all.xml.i5
-rw-r--r--op-mode-definitions/include/vni-tagnode.xml.i5
-rw-r--r--op-mode-definitions/nat.xml.in13
-rw-r--r--op-mode-definitions/show-evpn.xml.in59
-rw-r--r--python/vyos/version.py4
-rw-r--r--smoketest/config-tests/container-simple1
-rw-r--r--smoketest/configs/container-simple1
-rwxr-xr-xsrc/completion/list_esi.sh20
-rwxr-xr-xsrc/completion/list_vni.sh20
-rwxr-xr-xsrc/conf_mode/container.py11
-rwxr-xr-xsrc/conf_mode/nat_cgnat.py21
-rwxr-xr-xsrc/op_mode/cgnat.py75
-rw-r--r--src/op_mode/evpn.py46
15 files changed, 272 insertions, 19 deletions
diff --git a/data/op-mode-standardized.json b/data/op-mode-standardized.json
index a4ed2bcf4..c14133127 100644
--- a/data/op-mode-standardized.json
+++ b/data/op-mode-standardized.json
@@ -3,12 +3,14 @@
"bgp.py",
"bonding.py",
"bridge.py",
+"cgnat.py",
"config_mgmt.py",
"conntrack.py",
"container.py",
"cpu.py",
"dhcp.py",
"dns.py",
+"evpn.py",
"interfaces.py",
"ipsec.py",
"lldp.py",
diff --git a/interface-definitions/container.xml.in b/interface-definitions/container.xml.in
index e7dacea36..2296a3e9e 100644
--- a/interface-definitions/container.xml.in
+++ b/interface-definitions/container.xml.in
@@ -15,9 +15,15 @@
<constraintErrorMessage>Container name must be alphanumeric and can contain hyphens</constraintErrorMessage>
</properties>
<children>
+ <leafNode name="allow-host-pid">
+ <properties>
+ <help>Allow sharing host process namespace with container</help>
+ <valueless/>
+ </properties>
+ </leafNode>
<leafNode name="allow-host-networks">
<properties>
- <help>Allow host networks in container</help>
+ <help>Allow sharing host networking with container</help>
<valueless/>
</properties>
</leafNode>
diff --git a/op-mode-definitions/include/vni-tagnode-all.xml.i b/op-mode-definitions/include/vni-tagnode-all.xml.i
index 0fedb9371..fabab19d7 100644
--- a/op-mode-definitions/include/vni-tagnode-all.xml.i
+++ b/op-mode-definitions/include/vni-tagnode-all.xml.i
@@ -3,9 +3,10 @@
<properties>
<help>VXLAN network identifier (VNI) number</help>
<completionHelp>
- <list>1-16777215 all</list>
+ <list>&lt;1-16777215&gt; all</list>
+ <script>${vyos_completion_dir}/list_vni.sh</script>
</completionHelp>
</properties>
- <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>
+ <command>${vyos_op_scripts_dir}/evpn.py show_evpn --command "$*"</command>
</tagNode>
<!-- included end -->
diff --git a/op-mode-definitions/include/vni-tagnode.xml.i b/op-mode-definitions/include/vni-tagnode.xml.i
index 22f2d33bd..f5b99dcc8 100644
--- a/op-mode-definitions/include/vni-tagnode.xml.i
+++ b/op-mode-definitions/include/vni-tagnode.xml.i
@@ -3,9 +3,10 @@
<properties>
<help>VXLAN network identifier (VNI) number</help>
<completionHelp>
- <list>1-16777215</list>
+ <list>&lt;1-16777215&gt;</list>
+ <script>${vyos_completion_dir}/list_vni.sh</script>
</completionHelp>
</properties>
- <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>
+ <command>${vyos_op_scripts_dir}/evpn.py show_evpn --command "$*"</command>
</tagNode>
<!-- included end -->
diff --git a/op-mode-definitions/nat.xml.in b/op-mode-definitions/nat.xml.in
index 307a91337..6398c0e07 100644
--- a/op-mode-definitions/nat.xml.in
+++ b/op-mode-definitions/nat.xml.in
@@ -7,6 +7,19 @@
<help>Show IPv4 Network Address Translation (NAT) information</help>
</properties>
<children>
+ <node name="cgnat">
+ <properties>
+ <help>Show Carrier-Grade Network Address Translation (CGNAT)</help>
+ </properties>
+ <children>
+ <node name="allocation">
+ <properties>
+ <help>Show allocated CGNAT parameters</help>
+ </properties>
+ <command>sudo ${vyos_op_scripts_dir}/cgnat.py show_allocation</command>
+ </node>
+ </children>
+ </node>
<node name="source">
<properties>
<help>Show source IPv4 to IPv4 Network Address Translation (NAT) information</help>
diff --git a/op-mode-definitions/show-evpn.xml.in b/op-mode-definitions/show-evpn.xml.in
index a005cbc30..3c1e5c7d6 100644
--- a/op-mode-definitions/show-evpn.xml.in
+++ b/op-mode-definitions/show-evpn.xml.in
@@ -14,7 +14,7 @@
<children>
#include <include/frr-detail.xml.i>
</children>
- <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>
+ <command>${vyos_op_scripts_dir}/evpn.py show_evpn --command "$*"</command>
</node>
<tagNode name="access-vlan">
<properties>
@@ -31,7 +31,7 @@
<list>&lt;1-4094&gt;</list>
</completionHelp>
</properties>
- <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>
+ <command>${vyos_op_scripts_dir}/evpn.py show_evpn --command "$*"</command>
</node>
</children>
</tagNode>
@@ -43,6 +43,45 @@
#include <include/vni-tagnode-all.xml.i>
</children>
</node>
+ <tagNode name="es">
+ <properties>
+ <help>Show ESI information for specified ESI</help>
+ <completionHelp>
+ <list>&lt;esi&gt;</list>
+ <script>${vyos_completion_dir}/list_esi.sh</script>
+ </completionHelp>
+ </properties>
+ <command>${vyos_op_scripts_dir}/evpn.py show_evpn --command "$*"</command>
+ </tagNode>
+ <node name="es">
+ <properties>
+ <help>Show ESI information</help>
+ </properties>
+ <command>${vyos_op_scripts_dir}/evpn.py show_evpn --command "$*"</command>
+ <children>
+ <leafNode name="detail">
+ <properties>
+ <help>Show ESI details</help>
+ </properties>
+ <command>${vyos_op_scripts_dir}/evpn.py show_evpn --command "$*"</command>
+ </leafNode>
+ </children>
+ </node>
+ <node name="es-evi">
+ <properties>
+ <help>Show ESI information per EVI</help>
+ </properties>
+ <command>${vyos_op_scripts_dir}/evpn.py show_evpn --command "$*"</command>
+ <children>
+ <leafNode name="detail">
+ <properties>
+ <help>Show ESI per EVI details</help>
+ </properties>
+ <command>${vyos_op_scripts_dir}/evpn.py show_evpn --command "$*"</command>
+ </leafNode>
+ #include <include/vni-tagnode.xml.i>
+ </children>
+ </node>
<node name="mac">
<properties>
<help>MAC addresses</help>
@@ -67,7 +106,23 @@
#include <include/vni-tagnode-all.xml.i>
</children>
</node>
+ #include <include/vni-tagnode.xml.i>
+ <node name="vni">
+ <properties>
+ <help>Show VNI information</help>
+ </properties>
+ <command>${vyos_op_scripts_dir}/evpn.py show_evpn --command "$*"</command>
+ <children>
+ <leafNode name="detail">
+ <properties>
+ <help>Show VNI details</help>
+ </properties>
+ <command>${vyos_op_scripts_dir}/evpn.py show_evpn --command "$*"</command>
+ </leafNode>
+ </children>
+ </node>
</children>
+ <command>${vyos_op_scripts_dir}/evpn.py show_evpn --command "$*"</command>
</node>
</children>
</node>
diff --git a/python/vyos/version.py b/python/vyos/version.py
index 47a10e201..86e96d0ec 100644
--- a/python/vyos/version.py
+++ b/python/vyos/version.py
@@ -33,11 +33,11 @@ import os
import requests
import vyos.defaults
+from vyos.system.image import is_live_boot
from vyos.utils.file import read_file
from vyos.utils.file import read_json
from vyos.utils.process import popen
-from vyos.utils.process import run
from vyos.utils.process import DEVNULL
version_file = os.path.join(vyos.defaults.directories['data'], 'version.json')
@@ -85,7 +85,7 @@ def get_full_version_data(fname=version_file):
# In installed images, the squashfs image file is named after its image version,
# while on livecd it's just "filesystem.squashfs", that's how we tell a livecd boot
# from an installed image
- if run(""" grep -e '^overlay.*/filesystem.squashfs' /proc/mounts >/dev/null """) == 0:
+ if is_live_boot():
boot_via = "livecd"
else:
boot_via = "installed image"
diff --git a/smoketest/config-tests/container-simple b/smoketest/config-tests/container-simple
index 299af64cb..cc80ef4cf 100644
--- a/smoketest/config-tests/container-simple
+++ b/smoketest/config-tests/container-simple
@@ -8,5 +8,6 @@ set container name c01 capability 'net-bind-service'
set container name c01 capability 'net-raw'
set container name c01 image 'busybox:stable'
set container name c02 allow-host-networks
+set container name c02 allow-host-pid
set container name c02 capability 'sys-time'
set container name c02 image 'busybox:stable'
diff --git a/smoketest/configs/container-simple b/smoketest/configs/container-simple
index 05efe05e9..82983afb7 100644
--- a/smoketest/configs/container-simple
+++ b/smoketest/configs/container-simple
@@ -7,6 +7,7 @@ container {
}
name c02 {
allow-host-networks
+ allow-host-pid
cap-add sys-time
image busybox:stable
}
diff --git a/src/completion/list_esi.sh b/src/completion/list_esi.sh
new file mode 100755
index 000000000..b8373fa57
--- /dev/null
+++ b/src/completion/list_esi.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+#
+# Copyright (C) 2024 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 script is completion helper to list all valid ESEs that are visible to FRR
+
+esiJson=$(vtysh -c 'show evpn es json')
+echo "$(echo "$esiJson" | jq -r '.[] | .esi')"
diff --git a/src/completion/list_vni.sh b/src/completion/list_vni.sh
new file mode 100755
index 000000000..f8bd4a993
--- /dev/null
+++ b/src/completion/list_vni.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+#
+# Copyright (C) 2024 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 script is completion helper to list all configured VNIs that are visible to FRR
+
+vniJson=$(vtysh -c 'show evpn vni json')
+echo "$(echo "$vniJson" | jq -r 'keys | .[]')"
diff --git a/src/conf_mode/container.py b/src/conf_mode/container.py
index a73a18ffa..91a10e891 100755
--- a/src/conf_mode/container.py
+++ b/src/conf_mode/container.py
@@ -329,9 +329,13 @@ def generate_run_arguments(name, container_config):
prop = vol_config['propagation']
volume += f' --volume {svol}:{dvol}:{mode},{prop}'
+ host_pid = ''
+ if 'allow_host_pid' in container_config:
+ host_pid = '--pid host'
+
container_base_cmd = f'--detach --interactive --tty --replace {capabilities} ' \
f'--memory {memory}m --shm-size {shared_memory}m --memory-swap 0 --restart {restart} ' \
- f'--name {name} {hostname} {device} {port} {volume} {env_opt} {label} {uid}'
+ f'--name {name} {hostname} {device} {port} {volume} {env_opt} {label} {uid} {host_pid}'
entrypoint = ''
if 'entrypoint' in container_config:
@@ -339,11 +343,6 @@ def generate_run_arguments(name, container_config):
entrypoint = json_write(container_config['entrypoint'].split()).replace('"', "&quot;")
entrypoint = f'--entrypoint &apos;{entrypoint}&apos;'
- hostname = ''
- if 'host_name' in container_config:
- hostname = container_config['host_name']
- hostname = f'--hostname {hostname}'
-
command = ''
if 'command' in container_config:
command = container_config['command'].strip()
diff --git a/src/conf_mode/nat_cgnat.py b/src/conf_mode/nat_cgnat.py
index f41d66c66..9a20a3c54 100755
--- a/src/conf_mode/nat_cgnat.py
+++ b/src/conf_mode/nat_cgnat.py
@@ -203,6 +203,11 @@ def verify(config):
f'Range for "{pool} pool {pool_name}" must be defined!'
)
+ external_pools_query = "keys(pool.external)"
+ external_pools: list = jmespath.search(external_pools_query, config)
+ internal_pools_query = "keys(pool.internal)"
+ internal_pools: list = jmespath.search(internal_pools_query, config)
+
for rule, rule_config in config['rule'].items():
if 'source' not in rule_config:
raise ConfigError(f'Rule "{rule}" source pool must be defined!')
@@ -212,6 +217,14 @@ def verify(config):
if 'translation' not in rule_config:
raise ConfigError(f'Rule "{rule}" translation pool must be defined!')
+ internal_pool = rule_config['source']['pool']
+ if internal_pool not in internal_pools:
+ raise ConfigError(f'Internal pool "{internal_pool}" does not exist!')
+
+ external_pool = rule_config['translation']['pool']
+ if external_pool not in external_pools:
+ raise ConfigError(f'External pool "{external_pool}" does not exist!')
+
def generate(config):
if not config:
@@ -219,8 +232,8 @@ def generate(config):
# first external pool as we allow only one as PoC
ext_pool_name = jmespath.search("rule.*.translation | [0]", config).get('pool')
int_pool_name = jmespath.search("rule.*.source | [0]", config).get('pool')
- ext_query = f"pool.external.{ext_pool_name}.range | keys(@)"
- int_query = f"pool.internal.{int_pool_name}.range"
+ ext_query = f'pool.external."{ext_pool_name}".range | keys(@)'
+ int_query = f'pool.internal."{int_pool_name}".range'
external_ranges = jmespath.search(ext_query, config)
internal_ranges = [jmespath.search(int_query, config)]
@@ -246,10 +259,10 @@ def generate(config):
external_host_count = sum(external_list_count)
internal_host_count = sum(internal_list_count)
ports_per_user = int(
- jmespath.search(f'pool.external.{ext_pool_name}.per_user_limit.port', config)
+ jmespath.search(f'pool.external."{ext_pool_name}".per_user_limit.port', config)
)
external_port_range: str = jmespath.search(
- f'pool.external.{ext_pool_name}.external_port_range', config
+ f'pool.external."{ext_pool_name}".external_port_range', config
)
proto_maps, other_maps = generate_port_rules(
diff --git a/src/op_mode/cgnat.py b/src/op_mode/cgnat.py
new file mode 100755
index 000000000..a98269a15
--- /dev/null
+++ b/src/op_mode/cgnat.py
@@ -0,0 +1,75 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2024 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 json
+import sys
+import typing
+
+from tabulate import tabulate
+
+import vyos.opmode
+
+from vyos.configquery import ConfigTreeQuery
+from vyos.utils.process import cmd
+
+CGNAT_TABLE = 'cgnat'
+
+
+def _get_raw_data():
+ """ Get CGNAT dictionary
+ """
+ cmd_output = cmd(f'nft --json list table ip {CGNAT_TABLE}')
+ data = json.loads(cmd_output)
+ return data
+
+
+def _get_formatted_output(data):
+ elements = data['nftables'][2]['map']['elem']
+ allocations = []
+ for elem in elements:
+ internal = elem[0] # internal
+ external = elem[1]['concat'][0] # external
+ start_port = elem[1]['concat'][1]['range'][0]
+ end_port = elem[1]['concat'][1]['range'][1]
+ port_range = f'{start_port}-{end_port}'
+ allocations.append((internal, external, port_range))
+
+ headers = ['Internal IP', 'External IP', 'Port range']
+ output = tabulate(allocations, headers, numalign="left")
+ return output
+
+
+def show_allocation(raw: bool):
+ config = ConfigTreeQuery()
+ if not config.exists('nat cgnat'):
+ raise vyos.opmode.UnconfiguredSubsystem('CGNAT is not configured')
+
+ if raw:
+ return _get_raw_data()
+
+ else:
+ raw_data = _get_raw_data()
+ return _get_formatted_output(raw_data)
+
+
+if __name__ == '__main__':
+ try:
+ res = vyos.opmode.run(sys.modules[__name__])
+ if res:
+ print(res)
+ except (ValueError, vyos.opmode.Error) as e:
+ print(e)
+ sys.exit(1)
diff --git a/src/op_mode/evpn.py b/src/op_mode/evpn.py
new file mode 100644
index 000000000..cae4ab9f5
--- /dev/null
+++ b/src/op_mode/evpn.py
@@ -0,0 +1,46 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2016-2024 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 script is a helper to run VTYSH commands for "show evpn", allowing for the --raw flag to output JSON
+
+import sys
+import typing
+import json
+
+import vyos.opmode
+from vyos.utils.process import cmd
+
+def show_evpn(raw: bool, command: typing.Optional[str]):
+ if raw:
+ command = f"{command} json"
+ evpnDict = {}
+ try:
+ evpnDict['evpn'] = json.loads(cmd(f"vtysh -c '{command}'"))
+ except:
+ raise vyos.opmode.DataUnavailable(f"\"{command.replace(' json', '')}\" is invalid or has no JSON option")
+
+ return evpnDict
+ else:
+ return cmd(f"vtysh -c '{command}'")
+
+if __name__ == '__main__':
+ try:
+ res = vyos.opmode.run(sys.modules[__name__])
+ if res:
+ print(res)
+ except (ValueError, vyos.opmode.Error) as e:
+ print(e)
+ sys.exit(1)