diff --git a/interface-definitions/include/policy/route-common.xml.i b/interface-definitions/include/policy/route-common.xml.i
index 97795601eed..e0218c5dd78 100644
--- a/interface-definitions/include/policy/route-common.xml.i
+++ b/interface-definitions/include/policy/route-common.xml.i
@@ -128,6 +128,23 @@
+
+
+ VRF to forward packet with
+
+ default
+ Forward into default global VRF
+
+
+ txt
+ VRF instance name
+
+
+ vrf name
+
+ #include
+
+
TCP Maximum Segment Size
diff --git a/python/vyos/firewall.py b/python/vyos/firewall.py
index 664df28cc6d..c4116c8ce16 100644
--- a/python/vyos/firewall.py
+++ b/python/vyos/firewall.py
@@ -30,6 +30,7 @@
from vyos.utils.dict import dict_search_recursive
from vyos.utils.process import cmd
from vyos.utils.process import run
+from vyos.utils.network import get_vrf_table_id
# Conntrack
def conntrack_required(conf):
@@ -469,11 +470,20 @@ def parse_rule(rule_conf, hook, fw_name, rule_id, ip_name):
if 'mark' in rule_conf['set']:
mark = rule_conf['set']['mark']
output.append(f'meta mark set {mark}')
+ if 'vrf' in rule_conf['set']:
+ set_table = True
+ vrf_name = rule_conf['set']['vrf']
+ # NOTE: VRF->table ID lookup depends on the VRF iface already existing.
+ if vrf_name == 'default':
+ table = '254'
+ else:
+ table = get_vrf_table_id(vrf_name)
if 'table' in rule_conf['set']:
set_table = True
table = rule_conf['set']['table']
if table == 'main':
table = '254'
+ if set_table:
mark = 0x7FFFFFFF - int(table)
output.append(f'meta mark set {mark}')
if 'tcp_mss' in rule_conf['set']:
diff --git a/python/vyos/utils/network.py b/python/vyos/utils/network.py
index 829124b5721..398d7e07687 100644
--- a/python/vyos/utils/network.py
+++ b/python/vyos/utils/network.py
@@ -74,6 +74,9 @@ def get_vrf_members(vrf: str) -> list:
pass
return interfaces
+def get_vrf_table_id(vrf: str):
+ return get_interface_config(vrf)['linkinfo']['info_data']['table']
+
def get_interface_vrf(interface):
""" Returns VRF of given interface """
from vyos.utils.dict import dict_search
diff --git a/src/conf_mode/policy_route.py b/src/conf_mode/policy_route.py
index c58fe1bce72..e97282860f9 100755
--- a/src/conf_mode/policy_route.py
+++ b/src/conf_mode/policy_route.py
@@ -25,6 +25,7 @@
from vyos.utils.dict import dict_search_args
from vyos.utils.process import cmd
from vyos.utils.process import run
+from vyos.utils.network import get_vrf_table_id
from vyos import ConfigError
from vyos import airbag
airbag.enable()
@@ -83,6 +84,9 @@ def verify_rule(policy, name, rule_conf, ipv6, rule_id):
if not tcp_flags or 'syn' not in tcp_flags:
raise ConfigError(f'{name} rule {rule_id}: TCP SYN flag must be set to modify TCP-MSS')
+ if 'vrf' in rule_conf['set'] and 'table' in rule_conf['set']:
+ raise ConfigError(f'{name} rule {rule_id}: Cannot set both forwarding route table and VRF')
+
tcp_flags = dict_search_args(rule_conf, 'tcp', 'flags')
if tcp_flags:
if dict_search_args(rule_conf, 'protocol') != 'tcp':
@@ -152,15 +156,26 @@ def apply_table_marks(policy):
for name, pol_conf in policy[route].items():
if 'rule' in pol_conf:
for rule_id, rule_conf in pol_conf['rule'].items():
+ vrf_table_id = None
set_table = dict_search_args(rule_conf, 'set', 'table')
- if set_table:
+ set_vrf = dict_search_args(rule_conf, 'set', 'vrf')
+ if set_vrf:
+ if set_vrf == 'default':
+ vrf_table_id = '254'
+ else:
+ # str-cast so that tables uniqueness check works below.
+ vrf_table_id = str(get_vrf_table_id(set_vrf))
+ elif set_table:
if set_table == 'main':
- set_table = '254'
- if set_table in tables:
+ vrf_table_id = '254'
+ else:
+ vrf_table_id = set_table
+ if vrf_table_id is not None:
+ if vrf_table_id in tables:
continue
- tables.append(set_table)
- table_mark = mark_offset - int(set_table)
- cmd(f'{cmd_str} rule add pref {set_table} fwmark {table_mark} table {set_table}')
+ tables.append(vrf_table_id)
+ table_mark = mark_offset - int(vrf_table_id)
+ cmd(f'{cmd_str} rule add pref {vrf_table_id} fwmark {table_mark} table {vrf_table_id}')
def cleanup_table_marks():
for cmd_str in ['ip', 'ip -6']: