summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--data/templates/firewall/nftables-nat66.j212
-rw-r--r--data/templates/frr/bgpd.frr.j22
-rw-r--r--data/templates/macsec/wpa_supplicant.conf.j212
-rw-r--r--interface-definitions/include/bgp/protocol-common-config.xml.i2
-rw-r--r--interface-definitions/include/version/bgp-version.xml.i2
-rw-r--r--interface-definitions/nat66.xml.in73
-rw-r--r--python/vyos/configdict.py4
-rw-r--r--python/vyos/configverify.py13
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_macsec.py45
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_bgp.py28
-rwxr-xr-xsrc/conf_mode/interfaces-macsec.py11
-rwxr-xr-xsrc/conf_mode/protocols_bgp.py14
-rwxr-xr-xsrc/migration-scripts/bgp/2-to-351
-rwxr-xr-xsrc/validators/ipv6-address-exclude7
-rwxr-xr-xsrc/validators/ipv6-prefix-exclude7
15 files changed, 233 insertions, 50 deletions
diff --git a/data/templates/firewall/nftables-nat66.j2 b/data/templates/firewall/nftables-nat66.j2
index 003b138b2..ca19506f2 100644
--- a/data/templates/firewall/nftables-nat66.j2
+++ b/data/templates/firewall/nftables-nat66.j2
@@ -3,8 +3,10 @@
{% macro nptv6_rule(rule,config, chain) %}
{% set comment = '' %}
{% set base_log = '' %}
-{% set src_prefix = 'ip6 saddr ' ~ config.source.prefix if config.source.prefix is vyos_defined %}
-{% set dest_address = 'ip6 daddr ' ~ config.destination.address if config.destination.address is vyos_defined %}
+{% set dst_prefix = 'ip6 daddr ' ~ config.destination.prefix.replace('!','!= ') if config.destination.prefix is vyos_defined %}
+{% set src_prefix = 'ip6 saddr ' ~ config.source.prefix.replace('!','!= ') if config.source.prefix is vyos_defined %}
+{% set source_address = 'ip6 saddr ' ~ config.source.address.replace('!','!= ') if config.source.address is vyos_defined %}
+{% set dest_address = 'ip6 daddr ' ~ config.destination.address.replace('!','!= ') if config.destination.address is vyos_defined %}
{% if chain is vyos_defined('PREROUTING') %}
{% set comment = 'DST-NAT66-' ~ rule %}
{% set base_log = '[NAT66-DST-' ~ rule %}
@@ -52,6 +54,12 @@
{% if src_prefix is vyos_defined %}
{% set output = output ~ ' ' ~ src_prefix %}
{% endif %}
+{% if dst_prefix is vyos_defined %}
+{% set output = output ~ ' ' ~ dst_prefix %}
+{% endif %}
+{% if source_address is vyos_defined %}
+{% set output = output ~ ' ' ~ source_address %}
+{% endif %}
{% if dest_address is vyos_defined %}
{% set output = output ~ ' ' ~ dest_address %}
{% endif %}
diff --git a/data/templates/frr/bgpd.frr.j2 b/data/templates/frr/bgpd.frr.j2
index 7029f39af..2ab7c8596 100644
--- a/data/templates/frr/bgpd.frr.j2
+++ b/data/templates/frr/bgpd.frr.j2
@@ -231,7 +231,7 @@
{% endif %}
{% endmacro %}
!
-router bgp {{ local_as }} {{ 'vrf ' ~ vrf if vrf is vyos_defined }}
+router bgp {{ system_as }} {{ 'vrf ' ~ vrf if vrf is vyos_defined }}
{% if parameters.ebgp_requires_policy is vyos_defined %}
bgp ebgp-requires-policy
{% else %}
diff --git a/data/templates/macsec/wpa_supplicant.conf.j2 b/data/templates/macsec/wpa_supplicant.conf.j2
index d2529c50d..1f7ba16f4 100644
--- a/data/templates/macsec/wpa_supplicant.conf.j2
+++ b/data/templates/macsec/wpa_supplicant.conf.j2
@@ -47,6 +47,12 @@ network={
# 1: Integrity only
macsec_integ_only={{ '0' if security.encrypt is vyos_defined else '1' }}
+ # macsec_csindex: IEEE 802.1X/MACsec cipher suite
+ # 0 = GCM-AES-128
+ # 1 = GCM-AES-256
+{# security.cipher is a mandatory key #}
+ macsec_csindex={{ '1' if security.cipher is vyos_defined('gcm-aes-256') else '0' }}
+
{% if security.encrypt is vyos_defined %}
# mka_cak, mka_ckn, and mka_priority: IEEE 802.1X/MACsec pre-shared key mode
# This allows to configure MACsec with a pre-shared key using a (CAK,CKN) pair.
@@ -62,12 +68,6 @@ network={
# mka_priority (Priority of MKA Actor) is in 0..255 range with 255 being
# default priority
mka_priority={{ security.mka.priority }}
-
- # macsec_csindex: IEEE 802.1X/MACsec cipher suite
- # 0 = GCM-AES-128
- # 1 = GCM-AES-256
-{# security.cipher is a mandatory key #}
- macsec_csindex={{ '1' if security.cipher is vyos_defined('gcm-aes-256') else '0' }}
{% endif %}
{% if security.replay_window is vyos_defined %}
diff --git a/interface-definitions/include/bgp/protocol-common-config.xml.i b/interface-definitions/include/bgp/protocol-common-config.xml.i
index c1b465e43..d2bcea62a 100644
--- a/interface-definitions/include/bgp/protocol-common-config.xml.i
+++ b/interface-definitions/include/bgp/protocol-common-config.xml.i
@@ -896,7 +896,7 @@
</tagNode>
</children>
</node>
-<leafNode name="local-as">
+<leafNode name="system-as">
<properties>
<help>Autonomous System Number (ASN)</help>
<valueHelp>
diff --git a/interface-definitions/include/version/bgp-version.xml.i b/interface-definitions/include/version/bgp-version.xml.i
index 15bc5abd4..ced49e729 100644
--- a/interface-definitions/include/version/bgp-version.xml.i
+++ b/interface-definitions/include/version/bgp-version.xml.i
@@ -1,3 +1,3 @@
<!-- include start from include/version/bgp-version.xml.i -->
-<syntaxVersion component='bgp' version='2'></syntaxVersion>
+<syntaxVersion component='bgp' version='3'></syntaxVersion>
<!-- include end -->
diff --git a/interface-definitions/nat66.xml.in b/interface-definitions/nat66.xml.in
index b47f653c6..ac3198f45 100644
--- a/interface-definitions/nat66.xml.in
+++ b/interface-definitions/nat66.xml.in
@@ -49,6 +49,30 @@
</completionHelp>
</properties>
</leafNode>
+ <node name="destination">
+ <properties>
+ <help>IPv6 destination prefix options</help>
+ </properties>
+ <children>
+ <leafNode name="prefix">
+ <properties>
+ <help>IPv6 prefix to be translated</help>
+ <valueHelp>
+ <format>ipv6net</format>
+ <description>IPv6 prefix</description>
+ </valueHelp>
+ <valueHelp>
+ <format>!ipv6net</format>
+ <description>Match everything except the specified IPv6 prefix</description>
+ </valueHelp>
+ <constraint>
+ <validator name="ipv6-prefix"/>
+ <validator name="ipv6-prefix-exclude"/>
+ </constraint>
+ </properties>
+ </leafNode>
+ </children>
+ </node>
<node name="source">
<properties>
<help>IPv6 source prefix options</help>
@@ -61,8 +85,13 @@
<format>ipv6net</format>
<description>IPv6 prefix</description>
</valueHelp>
+ <valueHelp>
+ <format>!ipv6net</format>
+ <description>Match everything except the specified IPv6 prefix</description>
+ </valueHelp>
<constraint>
<validator name="ipv6-prefix"/>
+ <validator name="ipv6-prefix-exclude"/>
</constraint>
</properties>
</leafNode>
@@ -164,9 +193,53 @@
<format>ipv6net</format>
<description>IPv6 prefix</description>
</valueHelp>
+ <valueHelp>
+ <format>!ipv6</format>
+ <description>Match everything except the specified IPv6 address</description>
+ </valueHelp>
+ <valueHelp>
+ <format>!ipv6net</format>
+ <description>Match everything except the specified IPv6 prefix</description>
+ </valueHelp>
+ <constraint>
+ <validator name="ipv6-address"/>
+ <validator name="ipv6-prefix"/>
+ <validator name="ipv6-address-exclude"/>
+ <validator name="ipv6-prefix-exclude"/>
+ </constraint>
+ </properties>
+ </leafNode>
+ </children>
+ </node>
+ <node name="source">
+ <properties>
+ <help>IPv6 source prefix options</help>
+ </properties>
+ <children>
+ <leafNode name="address">
+ <properties>
+ <help>IPv6 address or prefix to be translated</help>
+ <valueHelp>
+ <format>ipv6</format>
+ <description>IPv6 address</description>
+ </valueHelp>
+ <valueHelp>
+ <format>ipv6net</format>
+ <description>IPv6 prefix</description>
+ </valueHelp>
+ <valueHelp>
+ <format>!ipv6</format>
+ <description>Match everything except the specified IPv6 address</description>
+ </valueHelp>
+ <valueHelp>
+ <format>!ipv6net</format>
+ <description>Match everything except the specified IPv6 prefix</description>
+ </valueHelp>
<constraint>
<validator name="ipv6-address"/>
<validator name="ipv6-prefix"/>
+ <validator name="ipv6-address-exclude"/>
+ <validator name="ipv6-prefix-exclude"/>
</constraint>
</properties>
</leafNode>
diff --git a/python/vyos/configdict.py b/python/vyos/configdict.py
index 20cc7de2a..8f822a97d 100644
--- a/python/vyos/configdict.py
+++ b/python/vyos/configdict.py
@@ -303,8 +303,8 @@ def is_source_interface(conf, interface, intftype=None):
for it in intftype:
base = ['interfaces', it]
for intf in conf.list_nodes(base):
- lower_intf = base + [intf, 'source-interface']
- if conf.exists(lower_intf) and interface in conf.return_values(lower_intf):
+ src_intf = base + [intf, 'source-interface']
+ if conf.exists(src_intf) and interface in conf.return_values(src_intf):
ret_val = intf
break
diff --git a/python/vyos/configverify.py b/python/vyos/configverify.py
index ac56da204..2ab3cb408 100644
--- a/python/vyos/configverify.py
+++ b/python/vyos/configverify.py
@@ -284,15 +284,16 @@ def verify_source_interface(config):
raise ConfigError('Specified source-interface {source_interface} does '
'not exist'.format(**config))
+ src_ifname = config['source_interface']
if 'source_interface_is_bridge_member' in config:
- raise ConfigError('Invalid source-interface {source_interface}. Interface '
- 'is already a member of bridge '
- '{source_interface_is_bridge_member}'.format(**config))
+ bridge_name = next(iter(config['source_interface_is_bridge_member']))
+ raise ConfigError(f'Invalid source-interface "{src_ifname}". Interface '
+ f'is already a member of bridge "{bridge_name}"!')
if 'source_interface_is_bond_member' in config:
- raise ConfigError('Invalid source-interface {source_interface}. Interface '
- 'is already a member of bond '
- '{source_interface_is_bond_member}'.format(**config))
+ bond_name = next(iter(config['source_interface_is_bond_member']))
+ raise ConfigError(f'Invalid source-interface "{src_ifname}". Interface '
+ f'is already a member of bond "{bond_name}"!')
def verify_dhcpv6(config):
"""
diff --git a/smoketest/scripts/cli/test_interfaces_macsec.py b/smoketest/scripts/cli/test_interfaces_macsec.py
index e5e5a558e..f141cc6d3 100755
--- a/smoketest/scripts/cli/test_interfaces_macsec.py
+++ b/smoketest/scripts/cli/test_interfaces_macsec.py
@@ -28,6 +28,8 @@ from vyos.util import read_file
from vyos.util import get_interface_config
from vyos.util import process_named_running
+PROCESS_NAME = 'wpa_supplicant'
+
def get_config_value(interface, key):
tmp = read_file(f'/run/wpa_supplicant/{interface}.conf')
tmp = re.findall(r'\n?{}=(.*)'.format(key), tmp)
@@ -55,6 +57,10 @@ class MACsecInterfaceTest(BasicInterfaceTest.TestCase):
# call base-classes classmethod
super(MACsecInterfaceTest, cls).setUpClass()
+ def tearDown(self):
+ super().tearDown()
+ self.assertFalse(process_named_running(PROCESS_NAME))
+
def test_macsec_encryption(self):
# MACsec can be operating in authentication and encryption mode - both
# using different mandatory settings, lets test encryption as the basic
@@ -96,28 +102,29 @@ class MACsecInterfaceTest(BasicInterfaceTest.TestCase):
self.cli_commit()
tmp = get_config_value(src_interface, 'macsec_integ_only')
- self.assertTrue("0" in tmp)
+ self.assertIn("0", tmp)
tmp = get_config_value(src_interface, 'mka_cak')
- self.assertTrue(mak_cak in tmp)
+ self.assertIn(mak_cak, tmp)
tmp = get_config_value(src_interface, 'mka_ckn')
- self.assertTrue(mak_ckn in tmp)
+ self.assertIn(mak_ckn, tmp)
# check that the default priority of 255 is programmed
tmp = get_config_value(src_interface, 'mka_priority')
- self.assertTrue("255" in tmp)
+ self.assertIn("255", tmp)
tmp = get_config_value(src_interface, 'macsec_replay_window')
- self.assertTrue(replay_window in tmp)
+ self.assertIn(replay_window, tmp)
tmp = read_file(f'/sys/class/net/{interface}/mtu')
self.assertEqual(tmp, '1460')
- # Check for running process
- self.assertTrue(process_named_running('wpa_supplicant'))
+ # Check for running process
+ self.assertTrue(process_named_running(PROCESS_NAME))
def test_macsec_gcm_aes_128(self):
+ src_interface = 'eth0'
interface = 'macsec1'
cipher = 'gcm-aes-128'
self.cli_set(self._base_path + [interface])
@@ -125,7 +132,7 @@ class MACsecInterfaceTest(BasicInterfaceTest.TestCase):
# check validate() - source interface is mandatory
with self.assertRaises(ConfigSessionError):
self.cli_commit()
- self.cli_set(self._base_path + [interface, 'source-interface', 'eth0'])
+ self.cli_set(self._base_path + [interface, 'source-interface', src_interface])
# check validate() - cipher is mandatory
with self.assertRaises(ConfigSessionError):
@@ -138,7 +145,15 @@ class MACsecInterfaceTest(BasicInterfaceTest.TestCase):
self.assertIn(interface, interfaces())
self.assertEqual(cipher, get_cipher(interface))
+ # check that we use the new macsec_csindex option (T4537)
+ tmp = get_config_value(src_interface, 'macsec_csindex')
+ self.assertIn("0", tmp)
+
+ # Check for running process
+ self.assertTrue(process_named_running(PROCESS_NAME))
+
def test_macsec_gcm_aes_256(self):
+ src_interface = 'eth0'
interface = 'macsec4'
cipher = 'gcm-aes-256'
self.cli_set(self._base_path + [interface])
@@ -146,7 +161,7 @@ class MACsecInterfaceTest(BasicInterfaceTest.TestCase):
# check validate() - source interface is mandatory
with self.assertRaises(ConfigSessionError):
self.cli_commit()
- self.cli_set(self._base_path + [interface, 'source-interface', 'eth0'])
+ self.cli_set(self._base_path + [interface, 'source-interface', src_interface])
# check validate() - cipher is mandatory
with self.assertRaises(ConfigSessionError):
@@ -158,6 +173,13 @@ class MACsecInterfaceTest(BasicInterfaceTest.TestCase):
self.assertIn(interface, interfaces())
self.assertEqual(cipher, get_cipher(interface))
+ # check that we use the new macsec_csindex option (T4537)
+ tmp = get_config_value(src_interface, 'macsec_csindex')
+ self.assertIn("1", tmp)
+
+ # Check for running process
+ self.assertTrue(process_named_running(PROCESS_NAME))
+
def test_macsec_source_interface(self):
# Ensure source-interface can bot be part of any other bond or bridge
@@ -186,6 +208,9 @@ class MACsecInterfaceTest(BasicInterfaceTest.TestCase):
self.cli_commit()
self.assertIn(interface, interfaces())
+ # Check for running process
+ self.assertTrue(process_named_running(PROCESS_NAME))
+
if __name__ == '__main__':
- unittest.main(verbosity=2)
+ unittest.main(verbosity=2, failfast=True)
diff --git a/smoketest/scripts/cli/test_protocols_bgp.py b/smoketest/scripts/cli/test_protocols_bgp.py
index 009dbc803..cefaad64a 100755
--- a/smoketest/scripts/cli/test_protocols_bgp.py
+++ b/smoketest/scripts/cli/test_protocols_bgp.py
@@ -46,7 +46,7 @@ neighbor_config = {
'shutdown' : '',
'cap_over' : '',
'ttl_security' : '5',
- 'local_as' : '300',
+ 'system_as' : '300',
'route_map_in' : route_map_in,
'route_map_out' : route_map_out,
'no_send_comm_ext' : '',
@@ -87,7 +87,7 @@ neighbor_config = {
'shutdown' : '',
'cap_over' : '',
'ttl_security' : '5',
- 'local_as' : '300',
+ 'system_as' : '300',
'solo' : '',
'route_map_in' : route_map_in,
'route_map_out' : route_map_out,
@@ -131,7 +131,7 @@ peer_group_config = {
'remote_as' : '200',
'shutdown' : '',
'no_cap_nego' : '',
- 'local_as' : '300',
+ 'system_as' : '300',
'pfx_list_in' : prefix_list_in,
'pfx_list_out' : prefix_list_out,
'no_send_comm_ext' : '',
@@ -177,7 +177,7 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
cls.cli_delete(cls, ['policy'])
def setUp(self):
- self.cli_set(base_path + ['local-as', ASN])
+ self.cli_set(base_path + ['system-as', ASN])
def tearDown(self):
self.cli_delete(['vrf'])
@@ -266,12 +266,12 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
self.cli_set(base_path + ['parameters', 'router-id', router_id])
self.cli_set(base_path + ['parameters', 'log-neighbor-changes'])
- # Local AS number MUST be defined - as this is set in setUp() we remove
+ # System AS number MUST be defined - as this is set in setUp() we remove
# this once for testing of the proper error
- self.cli_delete(base_path + ['local-as'])
+ self.cli_delete(base_path + ['system-as'])
with self.assertRaises(ConfigSessionError):
self.cli_commit()
- self.cli_set(base_path + ['local-as', ASN])
+ self.cli_set(base_path + ['system-as', ASN])
# Default local preference (higher = more preferred, default value is 100)
self.cli_set(base_path + ['parameters', 'default', 'local-pref', local_pref])
@@ -760,13 +760,13 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
# templates and Jinja2 FRR template.
table = '1000'
- self.cli_set(base_path + ['local-as', ASN])
+ self.cli_set(base_path + ['system-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])
- self.cli_set(vrf_base + ['protocols', 'bgp', 'local-as', ASN])
+ self.cli_set(vrf_base + ['protocols', 'bgp', 'system-as', ASN])
self.cli_set(vrf_base + ['protocols', 'bgp', 'parameters', 'router-id', router_id])
self.cli_set(vrf_base + ['protocols', 'bgp', 'route-map', route_map_in])
table = str(int(table) + 1000)
@@ -804,7 +804,7 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
confed_id = str(int(ASN) + 1)
confed_asns = '10 20 30 40'
- self.cli_set(base_path + ['local-as', ASN])
+ self.cli_set(base_path + ['system-as', ASN])
self.cli_set(base_path + ['parameters', 'router-id', router_id])
self.cli_set(base_path + ['parameters', 'confederation', 'identifier', confed_id])
for asn in confed_asns.split():
@@ -825,7 +825,7 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
remote_asn = str(int(ASN) + 10)
interface = 'eth0'
- self.cli_set(base_path + ['local-as', ASN])
+ self.cli_set(base_path + ['system-as', ASN])
self.cli_set(base_path + ['neighbor', interface, 'address-family', 'ipv6-unicast'])
self.cli_set(base_path + ['neighbor', interface, 'interface', 'v6only', 'remote-as', remote_asn])
@@ -850,7 +850,7 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
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 + ['system-as', ASN])
# 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'])
@@ -889,7 +889,7 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
peer_group = 'bar'
interface = 'eth0'
- self.cli_set(base_path + ['local-as', ASN])
+ self.cli_set(base_path + ['system-as', ASN])
self.cli_set(base_path + ['neighbor', neighbor, 'remote-as', remote_asn])
self.cli_set(base_path + ['neighbor', neighbor, 'peer-group', peer_group])
self.cli_set(base_path + ['peer-group', peer_group, 'remote-as', remote_asn])
@@ -929,7 +929,7 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
remote_asn = '500'
local_asn = '400'
- self.cli_set(base_path + ['local-as', ASN])
+ self.cli_set(base_path + ['system-as', ASN])
self.cli_set(base_path + ['neighbor', neighbor, 'remote-as', ASN])
self.cli_set(base_path + ['neighbor', neighbor, 'local-as', local_asn])
diff --git a/src/conf_mode/interfaces-macsec.py b/src/conf_mode/interfaces-macsec.py
index 65b0612ea..870049a88 100755
--- a/src/conf_mode/interfaces-macsec.py
+++ b/src/conf_mode/interfaces-macsec.py
@@ -22,6 +22,7 @@ from sys import exit
from vyos.config import Config
from vyos.configdict import get_interface_dict
from vyos.configdict import is_node_changed
+from vyos.configdict import is_source_interface
from vyos.configverify import verify_vrf
from vyos.configverify import verify_address
from vyos.configverify import verify_bridge_delete
@@ -65,6 +66,10 @@ def get_config(config=None):
if is_node_changed(conf, base + [ifname, 'source_interface']):
macsec.update({'shutdown_required': {}})
+ if 'source_interface' in macsec:
+ tmp = is_source_interface(conf, macsec['source_interface'], 'macsec')
+ if tmp and tmp != ifname: macsec.update({'is_source_interface' : tmp})
+
return macsec
@@ -97,6 +102,12 @@ def verify(macsec):
# gcm-aes-128 requires a 128bit long key - 64 characters (string) = 32byte = 256bit
raise ConfigError('gcm-aes-128 requires a 256bit long key!')
+ if 'is_source_interface' in macsec:
+ tmp = macsec['is_source_interface']
+ src_ifname = macsec['source_interface']
+ raise ConfigError(f'Can not use source-interface "{src_ifname}", it already ' \
+ f'belongs to interface "{tmp}"!')
+
if 'source_interface' in macsec:
# MACsec adds a 40 byte overhead (32 byte MACsec + 8 bytes VLAN 802.1ad
# and 802.1q) - we need to check the underlaying MTU if our configured
diff --git a/src/conf_mode/protocols_bgp.py b/src/conf_mode/protocols_bgp.py
index 7d3687094..87456f00b 100755
--- a/src/conf_mode/protocols_bgp.py
+++ b/src/conf_mode/protocols_bgp.py
@@ -121,8 +121,8 @@ def verify(bgp):
'dependent VRF instance(s) exist!')
return None
- if 'local_as' not in bgp:
- raise ConfigError('BGP local-as number must be defined!')
+ if 'system_as' not in bgp:
+ raise ConfigError('BGP system-as number must be defined!')
# Common verification for both peer-group and neighbor statements
for neighbor in ['neighbor', 'peer_group']:
@@ -147,8 +147,8 @@ def verify(bgp):
# Neighbor local-as override can not be the same as the local-as
# we use for this BGP instane!
asn = list(peer_config['local_as'].keys())[0]
- if asn == bgp['local_as']:
- raise ConfigError('Cannot have local-as same as BGP AS number')
+ if asn == bgp['system_as']:
+ raise ConfigError('Cannot have local-as same as system-as number')
# Neighbor AS specified for local-as and remote-as can not be the same
if dict_search('remote_as', peer_config) == asn:
@@ -216,7 +216,7 @@ def verify(bgp):
# Local-AS allowed only for EBGP peers
if 'local_as' in peer_config:
remote_as = verify_remote_as(peer_config, bgp)
- if remote_as == bgp['local_as']:
+ if remote_as == bgp['system_as']:
raise ConfigError(f'local-as configured for "{peer}", allowed only for eBGP peers!')
for afi in ['ipv4_unicast', 'ipv4_multicast', 'ipv4_labeled_unicast', 'ipv4_flowspec',
@@ -279,12 +279,12 @@ def verify(bgp):
verify_route_map(afi_config['route_map'][tmp], bgp)
if 'route_reflector_client' in afi_config:
- if 'remote_as' in peer_config and peer_config['remote_as'] != 'internal' and peer_config['remote_as'] != bgp['local_as']:
+ if 'remote_as' in peer_config and peer_config['remote_as'] != 'internal' and peer_config['remote_as'] != bgp['system_as']:
raise ConfigError('route-reflector-client only supported for iBGP peers')
else:
if 'peer_group' in peer_config:
peer_group_as = dict_search(f'peer_group.{peer_group}.remote_as', bgp)
- if peer_group_as != None and peer_group_as != 'internal' and peer_group_as != bgp['local_as']:
+ if peer_group_as != None and peer_group_as != 'internal' and peer_group_as != bgp['system_as']:
raise ConfigError('route-reflector-client only supported for iBGP peers')
# Throw an error if a peer group is not configured for allow range
diff --git a/src/migration-scripts/bgp/2-to-3 b/src/migration-scripts/bgp/2-to-3
new file mode 100755
index 000000000..7ced0a3b0
--- /dev/null
+++ b/src/migration-scripts/bgp/2-to-3
@@ -0,0 +1,51 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2022 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/>.
+
+# T4257: Discussion on changing BGP autonomous system number syntax
+
+from sys import argv
+from sys import exit
+
+from vyos.configtree import ConfigTree
+
+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()
+
+config = ConfigTree(config_file)
+
+# Check if BGP is even configured. Then check if local-as exists, then add the system-as, then remove the local-as. This is for global configuration.
+if config.exists(['protocols', 'bgp']):
+ if config.exists(['protocols', 'bgp', 'local-as']):
+ config.rename(['protocols', 'bgp', 'local-as'], 'system-as')
+
+# Check if vrf names are configured. Then check if local-as exists inside of a name, then add the system-as, then remove the local-as. This is for vrf configuration.
+if config.exists(['vrf', 'name']):
+ for vrf in config.list_nodes(['vrf', 'name']):
+ if config.exists(['vrf', f'name {vrf}', 'protocols', 'bgp', 'local-as']):
+ config.rename(['vrf', f'name {vrf}', 'protocols', 'bgp', 'local-as'], 'system-as')
+
+try:
+ with open(file_name, 'w') as f:
+ f.write(config.to_string())
+except OSError as e:
+ print(f'Failed to save the modified config: {e}')
+ exit(1)
diff --git a/src/validators/ipv6-address-exclude b/src/validators/ipv6-address-exclude
new file mode 100755
index 000000000..be1d3db25
--- /dev/null
+++ b/src/validators/ipv6-address-exclude
@@ -0,0 +1,7 @@
+#!/bin/sh
+arg="$1"
+if [ "${arg:0:1}" != "!" ]; then
+ exit 1
+fi
+path=$(dirname "$0")
+${path}/ipv6-address "${arg:1}"
diff --git a/src/validators/ipv6-prefix-exclude b/src/validators/ipv6-prefix-exclude
new file mode 100755
index 000000000..6fa4f1d8d
--- /dev/null
+++ b/src/validators/ipv6-prefix-exclude
@@ -0,0 +1,7 @@
+#!/bin/sh
+arg="$1"
+if [ "${arg:0:1}" != "!" ]; then
+ exit 1
+fi
+path=$(dirname "$0")
+${path}/ipv6-prefix "${arg:1}"