summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rwxr-xr-xsrc/conf_mode/container.py9
-rwxr-xr-xsrc/conf_mode/nat.py2
-rwxr-xr-xsrc/conf_mode/vrf.py21
-rwxr-xr-xsrc/op_mode/neighbor.py5
-rwxr-xr-xsrc/op_mode/vrf.py21
5 files changed, 32 insertions, 26 deletions
diff --git a/src/conf_mode/container.py b/src/conf_mode/container.py
index ed7cc809c..478868a9a 100755
--- a/src/conf_mode/container.py
+++ b/src/conf_mode/container.py
@@ -33,6 +33,7 @@ from vyos.utils.process import call
from vyos.utils.process import cmd
from vyos.utils.process import run
from vyos.utils.process import rc_cmd
+from vyos.template import bracketize_ipv6
from vyos.template import inc_ip
from vyos.template import is_ipv4
from vyos.template import is_ipv6
@@ -280,6 +281,14 @@ def generate_run_arguments(name, container_config):
protocol = container_config['port'][portmap]['protocol']
sport = container_config['port'][portmap]['source']
dport = container_config['port'][portmap]['destination']
+ listen_addresses = container_config['port'][portmap].get('listen_address', [])
+
+ # If listen_addresses is not empty, include them in the publish command
+ if listen_addresses:
+ for listen_address in listen_addresses:
+ port += f' --publish {bracketize_ipv6(listen_address)}:{sport}:{dport}/{protocol}'
+ else:
+ # If listen_addresses is empty, just include the standard publish command
port += f' --publish {sport}:{dport}/{protocol}'
# Bind volume
diff --git a/src/conf_mode/nat.py b/src/conf_mode/nat.py
index f9d711b36..9da7fbe80 100755
--- a/src/conf_mode/nat.py
+++ b/src/conf_mode/nat.py
@@ -224,7 +224,7 @@ def verify(nat):
elif config['inbound_interface'] not in 'any' and config['inbound_interface'] not in interfaces():
Warning(f'rule "{rule}" interface "{config["inbound_interface"]}" does not exist on this system')
- if not dict_search('translation.address', config) and not dict_search('translation.port', config) and not dict_search('translation.redirect.port', config):
+ if not dict_search('translation.address', config) and not dict_search('translation.port', config) and 'redirect' not in config['translation']:
if 'exclude' not in config and 'backend' not in config['load_balance']:
raise ConfigError(f'{err_msg} translation requires address and/or port')
diff --git a/src/conf_mode/vrf.py b/src/conf_mode/vrf.py
index be867b208..37625142c 100755
--- a/src/conf_mode/vrf.py
+++ b/src/conf_mode/vrf.py
@@ -28,6 +28,8 @@ from vyos.template import render
from vyos.template import render_to_string
from vyos.utils.dict import dict_search
from vyos.utils.network import get_interface_config
+from vyos.utils.network import get_vrf_members
+from vyos.utils.network import interface_exists
from vyos.utils.process import call
from vyos.utils.process import cmd
from vyos.utils.process import popen
@@ -143,7 +145,7 @@ def verify(vrf):
raise ConfigError(f'VRF "{name}" table id is mandatory!')
# routing table id can't be changed - OS restriction
- if os.path.isdir(f'/sys/class/net/{name}'):
+ if interface_exists(name):
tmp = str(dict_search('linkinfo.info_data.table', get_interface_config(name)))
if tmp and tmp != vrf_config['table']:
raise ConfigError(f'VRF "{name}" table id modification not possible!')
@@ -195,12 +197,23 @@ def apply(vrf):
sysctl_write('net.ipv4.udp_l3mdev_accept', bind_all)
for tmp in (dict_search('vrf_remove', vrf) or []):
- if os.path.isdir(f'/sys/class/net/{tmp}'):
- call(f'ip link delete dev {tmp}')
+ if interface_exists(tmp):
+ # T5492: deleting a VRF instance may leafe processes running
+ # (e.g. dhclient) as there is a depedency ordering issue in the CLI.
+ # We need to ensure that we stop the dhclient processes first so
+ # a proper DHCLP RELEASE message is sent
+ for interface in get_vrf_members(tmp):
+ vrf_iface = Interface(interface)
+ vrf_iface.set_dhcp(False)
+ vrf_iface.set_dhcpv6(False)
+
# Remove nftables conntrack zone map item
nft_del_element = f'delete element inet vrf_zones ct_iface_map {{ "{tmp}" }}'
cmd(f'nft {nft_del_element}')
+ # Delete the VRF Kernel interface
+ call(f'ip link delete dev {tmp}')
+
if 'name' in vrf:
# Separate VRFs in conntrack table
# check if table already exists
@@ -245,7 +258,7 @@ def apply(vrf):
for name, config in vrf['name'].items():
table = config['table']
- if not os.path.isdir(f'/sys/class/net/{name}'):
+ if not interface_exists(name):
# For each VRF apart from your default context create a VRF
# interface with a separate routing table
call(f'ip link add {name} type vrf table {table}')
diff --git a/src/op_mode/neighbor.py b/src/op_mode/neighbor.py
index 1edeb0045..8b3c45c7c 100755
--- a/src/op_mode/neighbor.py
+++ b/src/op_mode/neighbor.py
@@ -31,14 +31,11 @@ import sys
import typing
import vyos.opmode
+from vyos.utils.network import interface_exists
ArgFamily = typing.Literal['inet', 'inet6']
ArgState = typing.Literal['reachable', 'stale', 'failed', 'permanent']
-def interface_exists(interface):
- import os
- return os.path.exists(f'/sys/class/net/{interface}')
-
def get_raw_data(family, interface=None, state=None):
from json import loads
from vyos.utils.process import cmd
diff --git a/src/op_mode/vrf.py b/src/op_mode/vrf.py
index 1f0bbbaeb..51032a4b5 100755
--- a/src/op_mode/vrf.py
+++ b/src/op_mode/vrf.py
@@ -20,11 +20,11 @@ import sys
import typing
from tabulate import tabulate
+from vyos.utils.network import get_vrf_members
from vyos.utils.process import cmd
import vyos.opmode
-
def _get_raw_data(name=None):
"""
If vrf name is not set - get all VRFs
@@ -45,21 +45,6 @@ def _get_raw_data(name=None):
return data
-def _get_vrf_members(vrf: str) -> list:
- """
- Get list of interface VRF members
- :param vrf: str
- :return: list
- """
- output = cmd(f'ip --json --brief link show master {vrf}')
- answer = json.loads(output)
- interfaces = []
- for data in answer:
- if 'ifname' in data:
- interfaces.append(data.get('ifname'))
- return interfaces if len(interfaces) > 0 else ['n/a']
-
-
def _get_formatted_output(raw_data):
data_entries = []
for vrf in raw_data:
@@ -67,7 +52,9 @@ def _get_formatted_output(raw_data):
state = vrf.get('operstate').lower()
hw_address = vrf.get('address')
flags = ','.join(vrf.get('flags')).lower()
- members = ','.join(_get_vrf_members(name))
+ tmp = get_vrf_members(name)
+ if tmp: members = ','.join(get_vrf_members(name))
+ else: members = 'n/a'
data_entries.append([name, state, hw_address, flags, members])
headers = ["Name", "State", "MAC address", "Flags", "Interfaces"]