summaryrefslogtreecommitdiff
path: root/src/conf_mode/vrf.py
diff options
context:
space:
mode:
authorzsdc <taras@vyos.io>2021-07-12 22:59:48 +0300
committerzsdc <taras@vyos.io>2021-07-17 22:36:39 +0300
commit22791e26f444766dc9f9e1729b72893208f58079 (patch)
treee412fd0e8247c3fc11b9f90d33646aafaf29247c /src/conf_mode/vrf.py
parent83721c1ce672b76d40c710f38b0ab05c370a2191 (diff)
downloadvyos-1x-22791e26f444766dc9f9e1729b72893208f58079.tar.gz
vyos-1x-22791e26f444766dc9f9e1729b72893208f58079.zip
VRF: T3655: proper connection tracking for VRFs
Currently, all VRFs share the same connection tracking table, which can lead to problems: - traffic leaks to a wrong VRF - improper NAT rules handling when multiple VRFs contain the same IP networks - stateful firewall rules issues The commit implements connection tracking zones support. Each VRF utilizes its own zone, so connections will never mix up. It also adds some restrictions to VRF names and assigned table numbers, because of nftables and conntrack requirements: - VRF name should always start from a letter (interfaces that start from numbers are not supported in nftables rules) - table number must be in the 100-65535 range because conntrack supports only 65535 zones
Diffstat (limited to 'src/conf_mode/vrf.py')
-rwxr-xr-xsrc/conf_mode/vrf.py24
1 files changed, 24 insertions, 0 deletions
diff --git a/src/conf_mode/vrf.py b/src/conf_mode/vrf.py
index 936561edc..fbfce646f 100755
--- a/src/conf_mode/vrf.py
+++ b/src/conf_mode/vrf.py
@@ -18,6 +18,7 @@ import os
from sys import exit
from json import loads
+from tempfile import NamedTemporaryFile
from vyos.config import Config
from vyos.configdict import node_changed
@@ -26,6 +27,7 @@ from vyos.template import render
from vyos.template import render_to_string
from vyos.util import call
from vyos.util import cmd
+from vyos.util import popen
from vyos.util import dict_search
from vyos.util import get_interface_config
from vyos import ConfigError
@@ -125,11 +127,17 @@ def verify(vrf):
return None
+
def generate(vrf):
render(config_file, 'vrf/vrf.conf.tmpl', vrf)
vrf['new_frr_config'] = render_to_string('frr/vrf.frr.tmpl', vrf)
+ # Render nftables zones config
+ vrf['nft_vrf_zones'] = NamedTemporaryFile().name
+ render(vrf['nft_vrf_zones'], 'firewall/nftables-vrf-zones.tmpl', vrf)
+
return None
+
def apply(vrf):
# Documentation
#
@@ -151,8 +159,19 @@ def apply(vrf):
call(f'ip -4 route del vrf {tmp} unreachable default metric 4278198272')
call(f'ip -6 route del vrf {tmp} unreachable default metric 4278198272')
call(f'ip link delete dev {tmp}')
+ # 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}')
if 'name' in vrf:
+ # Separate VRFs in conntrack table
+ # check if table already exists
+ _, err = popen('nft list table inet vrf_zones')
+ # If not, create a table
+ if err:
+ cmd(f'nft -f {vrf["nft_vrf_zones"]}')
+ os.unlink(vrf['nft_vrf_zones'])
+
for name, config in vrf['name'].items():
table = config['table']
@@ -182,6 +201,9 @@ def apply(vrf):
# reconfiguration.
state = 'down' if 'disable' in config else 'up'
vrf_if.set_admin_state(state)
+ # Add nftables conntrack zone map item
+ nft_add_element = f'add element inet vrf_zones ct_iface_map {{ "{name}" : {table} }}'
+ cmd(f'nft {nft_add_element}')
# Linux routing uses rules to find tables - routing targets are then
# looked up in those tables. If the lookup got a matching route, the
@@ -214,6 +236,8 @@ def apply(vrf):
# clean out l3mdev-table rule if present
if 1000 in [r.get('priority') for r in list_rules() if r.get('priority') == 1000]:
call(f'ip {af} rule del pref 1000')
+ # Remove VRF zones table from nftables
+ cmd('nft delete table inet vrf_zones')
# add configuration to FRR
frr_cfg = frr.FRRConfig()