Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions data/templates/conntrackd/conntrackd.conf.j2
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ Sync {
UDP {
{% if listen_address is vyos_defined %}
{% for address in listen_address %}
IPv4_address {{ address }}
{{ 'IPv4_address' if address | is_ipv4 else 'IPv6_address' }} {{ address }}
{% endfor %}
{% endif %}
IPv4_Destination_Address {{ iface_config.peer }}
{{ 'IPv4_Destination_Address' if iface_config.peer | is_ipv4 else 'IPv6_Destination_Address' }} {{ iface_config.peer }}
Port {{ iface_config.port if iface_config.port is vyos_defined else '3780' }}
Interface {{ iface }}
SndSocketBuffer {{ sync_queue_size | int *1024 *1024 }}
Expand All @@ -24,10 +24,14 @@ Sync {
}
{% else %}
Multicast {
{% set ip_address = iface | get_ipv4 %}
{% if mcast_group | is_ipv6 %}
IPv6_address {{ mcast_group }}
{% else %}
{% set ip_address = iface | get_ipv4 %}
IPv4_address {{ mcast_group }}
Group {{ iface_config.port if iface_config.port is vyos_defined else '3780' }}
IPv4_interface {{ ip_address[0] | ip_from_cidr }}
{% endif %}
Group {{ iface_config.port if iface_config.port is vyos_defined else '3780' }}
Interface {{ iface }}
SndSocketBuffer {{ sync_queue_size | int *1024 *1024 }}
RcvSocketBuffer {{ sync_queue_size | int *1024 *1024 }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@
<help>DHCP high availability configuration</help>
</properties>
<children>
#include <include/source-address-ipv4.xml.i>
#include <include/source-address-ipv4-ipv6.xml.i>
<leafNode name="mode">
<properties>
<help>Configure high availability mode</help>
Expand All @@ -179,13 +179,17 @@
</leafNode>
<leafNode name="remote">
<properties>
<help>IPv4 remote address used for connection</help>
<help>Remote address for high availability peer</help>
<valueHelp>
<format>ipv4</format>
<description>IPv4 address of high availability peer</description>
</valueHelp>
<valueHelp>
<format>ipv6</format>
<description>IPv6 address of high availability peer</description>
</valueHelp>
<constraint>
<validator name="ipv4-address"/>
<validator name="ip-address"/>
</constraint>
</properties>
</leafNode>
Expand Down
20 changes: 17 additions & 3 deletions interface-definitions/service_conntrack-sync.xml.in
Original file line number Diff line number Diff line change
Expand Up @@ -148,23 +148,37 @@
<help>IP address of the peer to send the UDP conntrack info to. This disables multicast.</help>
<valueHelp>
<format>ipv4</format>
<description>IP address to listen for incoming connections</description>
<description>IPv4 address of conntrack synchronization peer</description>
</valueHelp>
<valueHelp>
<format>ipv6</format>
<description>IPv6 address of conntrack synchronization peer</description>
</valueHelp>
<constraint>
<validator name="ipv4-address"/>
<validator name="ip-address"/>
</constraint>
</properties>
</leafNode>
#include <include/port-number.xml.i>
</children>
</tagNode>
#include <include/listen-address-ipv4.xml.i>
#include <include/listen-address.xml.i>
<leafNode name="mcast-group">
<properties>
<help>Multicast group to use for syncing conntrack entries</help>
<valueHelp>
<format>ipv4</format>
<description>Multicast IPv4 group address</description>
</valueHelp>
<valueHelp>
<format>ipv6</format>
<description>Multicast IPv6 group address</description>
</valueHelp>
<constraint>
<validator name="ipv4-multicast"/>
<validator name="ipv6-multicast"/>
</constraint>
<constraintErrorMessage>Multicast IPv4/IPv6 address required</constraintErrorMessage>
</properties>
<defaultValue>225.0.0.50</defaultValue>
</leafNode>
Expand Down
25 changes: 13 additions & 12 deletions python/vyos/template.py
Original file line number Diff line number Diff line change
Expand Up @@ -908,18 +908,19 @@ def kea_high_availability_json(config):
'max-ack-delay': 5000,
'max-unacked-clients': 10,
'peers': [
{
'name': os.uname()[1],
'url': f'http://{source_addr}:647/',
'role': peer1_role,
'auto-failover': True
},
{
'name': config['name'],
'url': f'http://{remote_addr}:647/',
'role': peer2_role,
'auto-failover': True
}]
{
'name': os.uname()[1],
'url': f'http://{bracketize_ipv6(source_addr)}:647/',
'role': peer1_role,
'auto-failover': True,
},
{
'name': config['name'],
'url': f'http://{bracketize_ipv6(remote_addr)}:647/',
'role': peer2_role,
'auto-failover': True,
},
],
}

if 'ca_cert_file' in config:
Expand Down
43 changes: 39 additions & 4 deletions smoketest/scripts/cli/test_config_dependency.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

from vyos.utils.process import is_systemd_service_running
from vyos.utils.process import cmdl
from vyos.utils.file import read_file
from vyos.configsession import ConfigSessionError

from base_vyostest_shim import VyOSUnitTestSHIM
Expand Down Expand Up @@ -77,12 +78,14 @@ def test_configdep_prio_queue(self):
bonding_base = ['interfaces', 'bonding']
bond_interface = 'bond0'
bond_address = '192.0.2.1/24'
bond_ipv6_address = '2001:db8:9166::1/64'
vrrp_group_base = ['high-availability', 'vrrp', 'group']
vrrp_sync_group_base = ['high-availability', 'vrrp', 'sync-group']
vrrp_group = 'ETH2'
vrrp_sync_group = 'GROUP'
conntrack_sync_base = ['service', 'conntrack-sync']
conntrack_peer = '192.0.2.77'
conntrack_ipv6_peer = '2001:db8:9166::2'

# simple set to trigger in-session conntrack -> conntrack-sync
# dependency; note that this is triggered on boot in 1.4 due to
Expand All @@ -92,10 +95,9 @@ def test_configdep_prio_queue(self):
self.cli_set(['interfaces', 'ethernet', 'eth2', 'address',
'198.51.100.2/24'])

self.cli_set(bonding_base + [bond_interface, 'address',
bond_address])
self.cli_set(bonding_base + [bond_interface, 'member', 'interface',
'eth3'])
self.cli_set(bonding_base + [bond_interface, 'address', bond_address])
self.cli_set(bonding_base + [bond_interface, 'address', bond_ipv6_address])
self.cli_set(bonding_base + [bond_interface, 'member', 'interface', 'eth3'])

self.cli_set(vrrp_group_base + [vrrp_group, 'address',
'198.51.100.200/24'])
Expand All @@ -115,6 +117,39 @@ def test_configdep_prio_queue(self):

self.cli_commit()

config = read_file('/run/conntrackd/conntrackd.conf')
self.assertIn(f'IPv4_Destination_Address {conntrack_peer}', config)
self.assertTrue(is_systemd_service_running('conntrackd.service'))

# Test the IPv6 case
self.cli_delete(conntrack_sync_base + ['interface', bond_interface, 'peer'])
self.cli_set(
conntrack_sync_base
+ ['interface', bond_interface, 'peer', conntrack_ipv6_peer]
)
self.cli_set(
conntrack_sync_base + ['listen-address', bond_ipv6_address.split('/')[0]]
)

self.cli_commit()

config = read_file('/run/conntrackd/conntrackd.conf')
self.assertIn(f'IPv6_address {bond_ipv6_address.split("/")[0]}', config)
self.assertIn(f'IPv6_Destination_Address {conntrack_ipv6_peer}', config)
self.assertTrue(is_systemd_service_running('conntrackd.service'))

# Test IPv6 multicast
conntrack_ipv6_mcast_group = 'ff12::9166'
self.cli_delete(conntrack_sync_base + ['interface', bond_interface, 'peer'])
self.cli_delete(conntrack_sync_base + ['listen-address'])
self.cli_set(conntrack_sync_base + ['mcast-group', conntrack_ipv6_mcast_group])

self.cli_commit()

config = read_file('/run/conntrackd/conntrackd.conf')
self.assertIn(f'IPv6_address {conntrack_ipv6_mcast_group}', config)
self.assertTrue(is_systemd_service_running('conntrackd.service'))

# clean up
self.cli_delete(bonding_base)
self.cli_delete(vrrp_group_base)
Expand Down
15 changes: 15 additions & 0 deletions smoketest/scripts/cli/test_service_dhcp-server.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@
dns_1 = inc_ip(subnet, 2)
dns_2 = inc_ip(subnet, 3)
domain_name = 'vyos.net'
ha_ipv6_local = '2001:db8:9166::1'
ha_ipv6_remote = '2001:db8:9166::2'


class TestServiceDHCPServer(VyOSUnitTestSHIM.TestCase):
Expand All @@ -57,6 +59,9 @@ def setUpClass(cls):
cls.cli_set(
cls, ['interfaces', 'dummy', interface, 'address', f'{router}/{cidr_mask}']
)
cls.cli_set(
cls, ['interfaces', 'dummy', interface, 'address', f'{ha_ipv6_local}/64']
)

@classmethod
def tearDownClass(cls):
Expand Down Expand Up @@ -1234,6 +1239,16 @@ def test_dhcp_high_availability(self):
# Check for running process
self.verify_service_running()

# Test the IPv6 case
self.cli_set(base_path + ['high-availability', 'source-address', ha_ipv6_local])
self.cli_set(base_path + ['high-availability', 'remote', ha_ipv6_remote])
self.cli_commit()

config = read_file(KEA4_CONF)
self.assertIn(f'http://[{ha_ipv6_local}]:647/', config)
self.assertIn(f'http://[{ha_ipv6_remote}]:647/', config)
self.verify_service_running()

def test_dhcp_high_availability_standby(self):
shared_net_name = 'FAILOVER'
failover_name = 'VyOS-Failover'
Expand Down
28 changes: 25 additions & 3 deletions src/conf_mode/service_conntrack-sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
from vyos.utils.process import run
from vyos.template import render
from vyos.template import get_ipv4
from vyos.template import get_ipv6
from vyos.template import is_ipv4
from vyos.utils.network import is_addr_assigned
from vyos import ConfigError
from vyos import airbag
Expand Down Expand Up @@ -68,9 +70,6 @@ def verify(conntrack):
has_peer = False
for interface, interface_config in conntrack['interface'].items():
verify_interface_exists(conntrack, interface)
# Interface must not only exist, it must also carry an IP address
if len(get_ipv4(interface)) < 1:
raise ConfigError(f'Interface {interface} requires an IP address!')
if 'peer' in interface_config:
has_peer = True

Expand All @@ -82,6 +81,21 @@ def verify(conntrack):
if 'peer' not in interface_config:
raise ConfigError('Cannot mix unicast and multicast mode!')

# The synchronization interface must have an address matching the address
# family selected by its peer or multicast group.
for interface, interface_config in conntrack['interface'].items():
sync_address = (
interface_config['peer'] if has_peer else conntrack['mcast_group']
)
address_family = 'IPv4' if is_ipv4(sync_address) else 'IPv6'
interface_addresses = (
get_ipv4(interface) if is_ipv4(sync_address) else get_ipv6(interface)
)
if not interface_addresses:
raise ConfigError(
f'Interface {interface} requires an {address_family} address!'
)

if 'expect_sync' in conntrack:
if len(conntrack['expect_sync']) > 1 and 'all' in conntrack['expect_sync']:
raise ConfigError('Cannot configure expect-sync "all" with other protocols!')
Expand All @@ -90,6 +104,14 @@ def verify(conntrack):
for address in conntrack['listen_address']:
if not is_addr_assigned(address):
raise ConfigError(f'Specified listen-address {address} not assigned to any interface!')
if has_peer:
for interface_config in conntrack['interface'].values():
peer = interface_config['peer']
if is_ipv4(address) != is_ipv4(peer):
raise ConfigError(
f'Listen-address {address} does not match '
f'address-family of peer {peer}!'
)

vrrp_group = dict_search('failover_mechanism.vrrp.sync_group', conntrack)
if vrrp_group == None:
Expand Down
Loading