Skip to content

Commit

Permalink
syslog: T6989: add possibility to define VRF per remote
Browse files Browse the repository at this point in the history
Rsyslog supports individual VRFs per omfwd remote entry - so we should support
this, too.
  • Loading branch information
c-po committed Jan 18, 2025
1 parent e2944c1 commit 1840d1d
Show file tree
Hide file tree
Showing 7 changed files with 200 additions and 25 deletions.
10 changes: 5 additions & 5 deletions data/templates/rsyslog/rsyslog.conf.j2
Original file line number Diff line number Diff line change
Expand Up @@ -106,12 +106,11 @@ if prifilt("{{ tmp | join(',') }}") then {
template="SyslogProtocol23Format"
{% endif %}
TCP_Framing="{{ 'octed-counted' if remote_options.format.octet_counted is vyos_defined else 'traditional' }}"
{% if source_address is vyos_defined %}
# Sender IP address
Address="{{ source_address }}"
{% if remote_options.source_address is vyos_defined %}
Address="{{ remote_options.source_address }}"
{% endif %}
{% if vrf is vyos_defined %}
Device="{{ vrf }}"
{% if remote_options.vrf is vyos_defined %}
Device="{{ remote_options.vrf }}"
{% endif %}
)
}
Expand All @@ -121,3 +120,4 @@ if prifilt("{{ tmp | join(',') }}") then {

# Include all configuration files in /etc/rsyslog.d/
include(file="/etc/rsyslog.d/*.conf")

14 changes: 7 additions & 7 deletions interface-definitions/system_syslog.xml.in
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,6 @@
</valueHelp>
</properties>
<children>
#include <include/port-number.xml.i>
<leafNode name="port">
<defaultValue>514</defaultValue>
</leafNode>
#include <include/protocol-tcp-udp.xml.i>
#include <include/syslog-facility.xml.i>
<node name="format">
<properties>
Expand All @@ -63,6 +58,13 @@
</leafNode>
</children>
</node>
#include <include/port-number.xml.i>
<leafNode name="port">
<defaultValue>514</defaultValue>
</leafNode>
#include <include/protocol-tcp-udp.xml.i>
#include <include/source-address-ipv4-ipv6.xml.i>
#include <include/interface/vrf.xml.i>
</children>
</tagNode>
<node name="local">
Expand Down Expand Up @@ -100,8 +102,6 @@
<valueless/>
</properties>
</leafNode>
#include <include/source-address-ipv4-ipv6.xml.i>
#include <include/interface/vrf.xml.i>
</children>
</node>
</children>
Expand Down
25 changes: 25 additions & 0 deletions smoketest/config-tests/basic-syslog
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
set interfaces ethernet eth0 duplex 'auto'
set interfaces ethernet eth0 speed 'auto'
set interfaces ethernet eth1 address '172.16.33.154/24'
set interfaces ethernet eth1 duplex 'auto'
set interfaces ethernet eth1 speed 'auto'
set interfaces ethernet eth1 vrf 'red'
set system console device ttyS0 speed '115200'
set system domain-name 'vyos-ci-test.net'
set system host-name 'vyos'
set system login user vyos authentication encrypted-password '$6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0'
set system login user vyos authentication plaintext-password ''
set system syslog local facility all level 'info'
set system syslog local facility local7 level 'debug'
set system syslog marker interval '999'
set system syslog preserve-fqdn
set system syslog remote syslog01.vyos.net facility local7 level 'notice'
set system syslog remote syslog01.vyos.net port '8000'
set system syslog remote syslog01.vyos.net vrf 'red'
set system syslog remote syslog02.vyos.net facility all level 'debug'
set system syslog remote syslog02.vyos.net format include-timezone
set system syslog remote syslog02.vyos.net format octet-counted
set system syslog remote syslog02.vyos.net port '8001'
set system syslog remote syslog02.vyos.net protocol 'tcp'
set system syslog remote syslog02.vyos.net vrf 'red'
set vrf name red table '12321'
70 changes: 70 additions & 0 deletions smoketest/configs/basic-syslog
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
interfaces {
ethernet eth0 {
duplex "auto"
speed "auto"
}
ethernet eth1 {
address 172.16.33.154/24
duplex auto
speed auto
vrf red
}
}
system {
console {
device ttyS0 {
speed 115200
}
}
domain-name vyos-ci-test.net
host-name vyos
login {
user vyos {
authentication {
encrypted-password $6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0
plaintext-password ""
}
}
}
syslog {
global {
facility all {
level info
}
facility local7 {
level debug
}
marker {
interval 999
}
preserve-fqdn
}
host syslog01.vyos.net {
facility local7 {
level notice
}
port 8000
}
host syslog02.vyos.net {
facility all {
level debug
}
format {
include-timezone
octet-counted
}
protocol tcp
port 8001
}
vrf red
}
}
vrf {
name red {
table 12321
}
}

// Warning: Do not remove the following line.
// vyos-config-version: "bgp@5:broadcast-relay@1:cluster@2:config-management@1:conntrack@5:conntrack-sync@2:container@2:dhcp-relay@2:dhcp-server@8:dhcpv6-server@1:dns-dynamic@4:dns-forwarding@4:firewall@15:flow-accounting@1:https@6:ids@1:interfaces@32:ipoe-server@3:ipsec@13:isis@3:l2tp@9:lldp@2:mdns@1:monitoring@1:nat@8:nat66@3:ntp@3:openconnect@3:ospf@2:pim@1:policy@8:pppoe-server@10:pptp@5:qos@2:quagga@11:reverse-proxy@1:rip@1:rpki@2:salt@1:snmp@3:ssh@2:sstp@6:system@27:vrf@3:vrrp@4:vyos-accel-ppp@2:wanloadbalance@3:webproxy@2"
// Release version: 1.4.0
64 changes: 64 additions & 0 deletions smoketest/scripts/cli/test_system_syslog.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ def setUpClass(cls):
# ensure we can also run this test on a live system - so lets clean
# out the current configuration :)
cls.cli_delete(cls, base_path)
cls.cli_delete(cls, ['vrf'])

def tearDown(self):
# Check for running process
Expand Down Expand Up @@ -204,5 +205,68 @@ def test_remote(self):
else:
self.assertIn( ' TCP_Framing="traditional"', config)

def test_vrf_source_address(self):
rhosts = {
'169.254.0.10': { },
'169.254.0.11': {
'vrf': {'name' : 'red', 'table' : '12321'},
'source_address' : '169.254.0.11',
},
'169.254.0.12': {
'vrf': {'name' : 'green', 'table' : '12322'},
'source_address' : '169.254.0.12',
},
'169.254.0.13': {
'vrf': {'name' : 'blue', 'table' : '12323'},
'source_address' : '169.254.0.13',
},
}

for remote, remote_options in rhosts.items():
remote_base = base_path + ['remote', remote]
self.cli_set(remote_base + ['facility', 'all'])

vrf = None
if 'vrf' in remote_options:
vrf = remote_options['vrf']['name']
self.cli_set(['vrf', 'name', vrf, 'table', remote_options['vrf']['table']])
self.cli_set(remote_base + ['vrf', vrf])

if 'source_address' in remote_options:
source_address = remote_options['source_address']
self.cli_set(remote_base + ['source-address', source_address])

idx = source_address.split('.')[-1]
self.cli_set(['interfaces', 'dummy', f'dum{idx}', 'address', f'{source_address}/32'])
if vrf:
self.cli_set(['interfaces', 'dummy', f'dum{idx}', 'vrf', vrf])


self.cli_commit()
config = read_file(RSYSLOG_CONF)

for remote, remote_options in rhosts.items():
config = get_config(f'# Remote syslog to {remote}')

self.assertIn(f'target="{remote}"', config)
if 'vrf' in remote_options:
vrf = remote_options['vrf']['name']
self.assertIn(f'Device="{vrf}"', config)

if 'source_address' in remote_options:
source_address = remote_options['source_address']
self.assertIn(f'Address="{source_address}"', config)

# Cleanup VRF/Dummy interfaces
for remote, remote_options in rhosts.items():
if 'vrf' in remote_options:
vrf = remote_options['vrf']['name']
self.cli_delete(['vrf', 'name', vrf])

if 'source_address' in remote_options:
source_address = remote_options['source_address']
idx = source_address.split('.')[-1]
self.cli_delete(['interfaces', 'dummy', f'dum{idx}'])

if __name__ == '__main__':
unittest.main(verbosity=2)
35 changes: 22 additions & 13 deletions src/conf_mode/system_syslog.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
from vyos.utils.network import is_addr_assigned
from vyos.utils.process import call
from vyos.template import render
from vyos.template import is_ipv4
from vyos.template import is_ipv6
from vyos import ConfigError
from vyos import airbag
airbag.enable()
Expand Down Expand Up @@ -74,19 +76,26 @@ def verify(syslog):
Warning('No "system domain-name" defined - cannot set syslog FQDN!')

if 'remote' in syslog:
for host, host_options in syslog['remote'].items():
if 'protocol' in host_options and host_options['protocol'] == 'udp':
if 'format' in host_options and 'octet_counted' in host_options['format']:
Warning(f'Syslog UDP transport for "{host}" should not use octet-counted format!')

verify_vrf(syslog)

if 'source_address' in syslog:
syslog_vrf = None
if 'vrf' in syslog:
syslog_vrf = syslog['vrf']
if not is_addr_assigned(syslog['source_address'], syslog_vrf):
raise ConfigError('No interface with given address specified!')
for remote, remote_options in syslog['remote'].items():
if 'protocol' in remote_options and remote_options['protocol'] == 'udp':
if 'format' in remote_options and 'octet_counted' in remote_options['format']:
Warning(f'Syslog UDP transport for "{remote}" should not use octet-counted format!')

if 'vrf' in remote_options:
verify_vrf(remote_options)

if 'source_address' in remote_options:
vrf = None
if 'vrf' in remote_options:
vrf = remote_options['vrf']
if not is_addr_assigned(remote_options['source_address'], vrf):
raise ConfigError('No interface with given address specified!')

source_address = remote_options['source_address']
if ((is_ipv4(remote) and is_ipv6(source_address)) or
(is_ipv6(remote) and is_ipv4(source_address))):
raise ConfigError(f'Source-address "{source_address}" does not match '\
f'address-family of remote "{remote}"!')

def generate(syslog):
if not syslog:
Expand Down
7 changes: 7 additions & 0 deletions src/migration-scripts/system/28-to-29
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,18 @@ def migrate(config: ConfigTree) -> None:
if config.exists(base + ['global']):
config.rename(base + ['global'], 'local')

vrf = ''
if config.exists(base + ['vrf']):
vrf = config.return_value(base + ['vrf'])
config.delete(base + ['vrf'])

# Rename host x.x.x.x -> remote x.x.x.x
if config.exists(base + ['host']):
config.set(base + ['remote'])
config.set_tag(base + ['remote'])
for remote in config.list_nodes(base + ['host']):
config.copy(base + ['host', remote], base + ['remote', remote])
config.set_tag(base + ['remote'])
if vrf:
config.set(base + ['remote', remote, 'vrf'], value=vrf)
config.delete(base + ['host'])

0 comments on commit 1840d1d

Please sign in to comment.