Page MenuHomeVyOS Platform

Use a vmap for Zone based firewall config
Open, NormalPublicFEATURE REQUEST

Description

Currently, the zone based config has a single line for a zone peering, along with one line for intra-zone traffic. This scales very poorly, especially when there are a large number of zones. This will slow down the processing of traffic dramatically when there are a large number of peerings. With only 10 zones, that can potentially create 90 zone pairings, plus 10 intra-zone rules, for a total of 100 rules.

Vmaps can solve this by using a hash-map of jump targets, allowing for traffic to only need to traverse a single rule rather than 100. Traffic enters the vmap, and looks up the hash for the iifname and oifname pairing, and jumps to the appropriate chain.

Config:
set firewall ipv4 name A_B default-action 'accept'
set firewall ipv4 name A_C default-action 'accept'
set firewall ipv4 name A_D default-action 'accept'
set firewall ipv4 name A_E default-action 'accept'
set firewall ipv4 name A_F default-action 'accept'
set firewall ipv4 name A_G default-action 'accept'

set firewall zone A from B firewall name 'A_B'
set firewall zone A from C firewall name 'A_C'
set firewall zone A from D firewall name 'A_D'
set firewall zone A from E firewall name 'A_E'
set firewall zone A from F firewall name 'A_F'
set firewall zone A from G firewall name 'A_G'
set firewall zone A interface 'eth0.100'
set firewall zone A intra-zone-filtering action 'drop'
set firewall zone B interface 'eth0.101'
set firewall zone C interface 'eth0.102'
set firewall zone D interface 'eth0.103'
set firewall zone E interface 'eth0.104'
set firewall zone F interface 'eth0.105'
set firewall zone G interface 'eth0.106'
Existing nft config that is generated:

You can see that I only have explicit zone pairings from zone 'A' to the other zones, and don't even have the return pairings, or any other pairings like 'B' to 'C'. Even with that, there are still 7 rules to traverse in VYOS_ZONE_FORWARD , along with 15 rules in VZONE_A

table ip vyos_filter {
        chain NAME_A_B {
                counter accept comment "NAM-A_B default-action accept"
        }

        chain NAME_A_C {
                counter accept comment "NAM-A_C default-action accept"
        }

        chain NAME_A_D {
                counter accept comment "NAM-A_D default-action accept"
        }

        chain NAME_A_E {
                counter accept comment "NAM-A_E default-action accept"
        }

        chain NAME_A_F {
                counter accept comment "NAM-A_F default-action accept"
        }

        chain NAME_A_G {
                counter accept comment "NAM-A_G default-action accept"
        }

        chain VYOS_ZONE_FORWARD {
                type filter hook forward priority filter + 1; policy accept;
                oifname "eth0.100" counter jump VZONE_A
                oifname "eth0.101" counter jump VZONE_B
                oifname "eth0.102" counter jump VZONE_C
                oifname "eth0.103" counter jump VZONE_D
                oifname "eth0.104" counter jump VZONE_E
                oifname "eth0.105" counter jump VZONE_F
                oifname "eth0.106" counter jump VZONE_G
        }

        chain VYOS_ZONE_LOCAL {
                type filter hook input priority filter + 1; policy accept;
        }

        chain VYOS_ZONE_OUTPUT {
                type filter hook output priority filter + 1; policy accept;
        }

        chain VZONE_A {
                iifname "eth0.100" counter drop
                iifname "eth0.100" counter return
                iifname "eth0.101" counter jump NAME_A_B
                iifname "eth0.101" counter return
                iifname "eth0.102" counter jump NAME_A_C
                iifname "eth0.102" counter return
                iifname "eth0.103" counter jump NAME_A_D
                iifname "eth0.103" counter return
                iifname "eth0.104" counter jump NAME_A_E
                iifname "eth0.104" counter return
                iifname "eth0.105" counter jump NAME_A_F
                iifname "eth0.105" counter return
                iifname "eth0.106" counter jump NAME_A_G
                iifname "eth0.106" counter return
                counter drop comment "zone_A default-action drop"
        }

        chain VZONE_B {
                iifname "eth0.101" counter return
                counter drop comment "zone_B default-action drop"
        }

        chain VZONE_C {
                iifname "eth0.102" counter return
                counter drop comment "zone_C default-action drop"
        }

        chain VZONE_D {
                iifname "eth0.103" counter return
                counter drop comment "zone_D default-action drop"
        }

        chain VZONE_E {
                iifname "eth0.104" counter return
                counter drop comment "zone_E default-action drop"
        }

        chain VZONE_F {
                iifname "eth0.105" counter return
                counter drop comment "zone_F default-action drop"
        }

        chain VZONE_G {
                iifname "eth0.106" counter return
                counter drop comment "zone_G default-action drop"
        }
}
Proposed change to the generated nft config:

In this solution, all of the VZONE chains are removed in favor of a single vmap. A single rule in VYOS_ZONE_FORWARD is used to enter the vmap. This is radically more efficient when processing traffic. Even with this minimal config of 6 zone pairings, you'd see efficiency gains.

table ip vyos_filter {
        map zone_fwd {
                type ifname . ifname : verdict
                counter
                elements = { "eth0.100" . "eth0.100" counter : drop,
                             "eth0.100" . "eth0.101" counter : jump NAME_A_B,
                             "eth0.101" . "eth0.101" counter : return,
                             "eth0.100" . "eth0.102" counter : jump NAME_A_C,
                             "eth0.102" . "eth0.102" counter : return,
                             "eth0.100" . "eth0.103" counter : jump NAME_A_D,
                             "eth0.103" . "eth0.103" counter : return,
                             "eth0.100" . "eth0.104" counter : jump NAME_A_E,
                             "eth0.104" . "eth0.104" counter : return,
                             "eth0.100" . "eth0.105" counter : jump NAME_A_F,
                             "eth0.105" . "eth0.105" counter : return,
                             "eth0.100" . "eth0.106" counter : jump NAME_A_G,
                             "eth0.106" . "eth0.106" counter : return }
        }

        chain NAME_A_B {
                counter accept comment "NAM-A_B default-action accept"
        }

        chain NAME_A_C {
                counter accept comment "NAM-A_C default-action accept"
        }

        chain NAME_A_D {
                counter accept comment "NAM-A_D default-action accept"
        }

        chain NAME_A_E {
                counter accept comment "NAM-A_E default-action accept"
        }

        chain NAME_A_F {
                counter accept comment "NAM-A_F default-action accept"
        }

        chain NAME_A_G {
                counter accept comment "NAM-A_G default-action accept"
        }

        chain VYOS_ZONE_FORWARD {
                type filter hook forward priority filter + 1; policy accept;
                oifname . iifname vmap @zone_fwd
                counter log prefix "[default-drop]" drop comment "zone default-action drop"
        }

        chain VYOS_ZONE_LOCAL {
                type filter hook input priority filter + 1; policy accept;
        }

        chain VYOS_ZONE_OUTPUT {
                type filter hook output priority filter + 1; policy accept;
        }
}

Details

Version
-
Is it a breaking change?
Unspecified (possibly destroys the router)
Issue type
Feature (new functionality)