Page MenuHomeVyOS Platform

firewall: Move source-validation rules into a vmap to improve traffic processing speed.
In progress, LowPublic

Description

Currently, the per-interface source-validation rules create 2 nftables rules per interface (one rule to match and one rule to exit the processing early). This scales poorly with a large number of interfaces. If a user has 20 wireguard interfaces (wg1-20) where they want strict uRPF, but have multiple WAN interfaces that they are okay with being asymmetric, then they must apply the strict policy only on the wireguard interfaces. 20 interfaces would create 40 rules. This means traffic that hits the last wireguard interface would traverse 40 rules.

By moving the validation config to vmaps, this means at worst there would be 3 rules that are needed to traverse, which would be a per-interface strict rule, a per-interface loose rule, and a global rule. More typically there'd only be one to 2 rules....a huge improvement over the existing 41 rules that would be processed worst case (40 per-interface rules + the global rule).

Existing implementation (10 interfaces set to strict; no global policy):
table ip raw {
        chain vyos_global_rpfilter {
                return
        }

        chain vyos_rpfilter {
                type filter hook prerouting priority raw; policy accept;
                iifname "eth2.210" fib saddr . iif oif 0 counter drop
                iifname "eth2.210" counter return
                iifname "eth2.209" fib saddr . iif oif 0 counter drop
                iifname "eth2.209" counter return
                iifname "eth2.208" fib saddr . iif oif 0 counter drop
                iifname "eth2.208" counter return
                iifname "eth2.207" fib saddr . iif oif 0 counter drop
                iifname "eth2.207" counter return
                iifname "eth2.206" fib saddr . iif oif 0 counter drop
                iifname "eth2.206" counter return
                iifname "eth2.205" fib saddr . iif oif 0 counter drop
                iifname "eth2.205" counter return
                iifname "eth2.204" fib saddr . iif oif 0 counter drop
                iifname "eth2.204" counter return
                iifname "eth2.203" fib saddr . iif oif 0 counter drop
                iifname "eth2.203" counter return
                iifname "eth2.202" fib saddr . iif oif 0 counter drop
                iifname "eth2.202" counter return
                iifname "eth2.201" fib saddr . iif oif 0 counter drop
                iifname "eth2.201" counter return
                counter jump vyos_global_rpfilter
        }
}
Proposed implementation (10 interfaces set to strict; no global policy):
table ip raw {
        map rpfilter_strict {
                typeof fib saddr . iif oif : verdict
                counter
                elements = {
                    0      : drop,
                    "eth2.201" : accept,
                    "eth2.202" : accept,
                    "eth2.203" : accept,
                    "eth2.204" : accept,
                    "eth2.205" : accept,
                    "eth2.206" : accept,
                    "eth2.207" : accept,
                    "eth2.208" : accept,
                    "eth2.209" : accept,
                    "eth2.210" : accept
                }
        }

        map rpfilter_loose {
                typeof fib saddr oif : verdict
                counter
        }

        set rpfilter_strict_ifaces {
                type ifname
                flags constant
                elements = { 
                    "eth2.201", 
                    "eth2.202", 
                    "eth2.203", 
                    "eth2.204", 
                    "eth2.205", 
                    "eth2.206", 
                    "eth2.207", 
                    "eth2.208", 
                    "eth2.209", 
                    "eth2.2010" 
                }
        }

        set rpfilter_loose_ifaces {
                type ifname
                flags constant
        }

        chain vyos_global_rpfilter {
        }

        chain vyos_rpfilter {
                type filter hook prerouting priority raw; policy accept;
                iifname @rpfilter_strict_ifaces fib saddr . iif oif vmap @rpfilter_strict    
                counter jump vyos_global_rpfilter

        }
}
NOTE: The return in vyos_global_rpfilter would also be removed since that behavior already happens at the end of the chain and would just cause extra processing. While the processing time would be tiny, it can add up as this behavior exists throughput VyOS' nftables implentation.

Details

Version
-
Is it a breaking change?
Unspecified (possibly destroys the router)
Issue type
Performance optimization