What does the vrf switch in /routing/ruledo? It seems to be rather new and undocumented. The CLI reference mentions it, but doesn't provide a description.
I'm familiar with VRF in general, but don't understand what this switch does in this context.
It is implemented, and in reality it always was there, just not exposed to the user.
So, if you want to know what it is, it's story time.
Mikrotik, under the hood is Linux, just a modified one. (Whether you consider these modifications heavy or light will depend on what features you're looking at.) In the Linuxy world, all routing is done according to routing rules. The "ip ..." set of commands gives you access to these. On most normal computers you don't really interact with these, and even the Linux interface is somewhat constructed to shield you from having to know about them if you don't have a specific reason to mess with them.
E.g. on a normal Ubunti:
# ip rule show
0: from all lookup local
32766: from all lookup main
32767: from all lookup default
This looks suspiciously like the new /routing rule interface.
Having learnt all of this, what is this vrf action?
We have to first know that a VRF in linux world is a special routing table that has netdevs bound to it. In the Mikrotik world, this is shown as interfaces (the netdevs) being a part of an IP->VRF (which is a list of these special routing tables.)
The point of VRFs is that the packets coming from the interfaces that are part fo them are routed according to these special routing tables.
This is what the vrf action represents: if the ingress interface is part of a vrf, consult the routing table attached to it.
Hm, that's the default behaviour anyway. Why would you need a routing rule for that? Also, all interfaces are members of a VRF. If you don't explicitly specify one, it's the main VRF.
Could you provide an example where adding the vrf option to a routing rule changes its behaviour?
This is sophistry. You can view it in two ways (you can pick either.)
That packets coming from a bound netdev are to be looked up in the vrf's routing table is not the default behavior as codified in the Linux kernel (i.e. in the actual code.) What is in the kernel is that the routing rules should be iterated over (according to their associated priority, as seem in the ip rule listing) and decisions are to be made as specified by them.
From this it follows, that if you move the default vrf rules to the bottom of the list of rules, this claimed-to-be-default behavior ceases.
It can also be said that this is indeed the default behavior, in the sense that this rule was always present (and similar rules are automatically added on Linux machines when constructing a vrf) and this rule is in fact what specifies this default. It just wasn't visible until now.
process policy routing rules (lookup routing-marks set by ip/firewall/mangle, If lookup fails move to the next rule).
check that the packet has to be resolved in a VRF other than "main", and try to resolve it, return "network unreachable" if cannot be resolved here
check that the packet has to be locally delivered, the destination address is the address of the router from the "main" VRF
process implicit policy routing rules (any user defined rules by default is added in "user" chain)
process implicit catch-all rule that looks up the destination in the ''main'' routing table
the returned result is "network unreachable"
accompanied by this image:
The rules that are now visible are what are labeled as "implicit rules".
The more productive question would be: why are these shown now? It's mainly to allow people to rearrange the rules, as is sometimes very convenient. If this doesn't apply to you, no worries, the default is still the sefault.
Thanks @CGGXANNX, that was actually helpful! Your longer post is something I'd wish to find in the official documentation.
What I've also learned from this is that by default, user defined policy routing rules are ignored if the interface is in a VRF other than main, because the vrf-lookup / vrf-unreach chains have a higher priority than the user chain. Correct? So if you need policy routing rules on VRF interfaces, you'll have to explicitly specify a higher priority chain (mangle) in the rules, or move the user chain to a higher priority globally, or create a custom chain, correct?
Yes, and before 7.22 you could not do that, so if you have VRF interfaces, only mangle rules was usable for policy routing on them, like you wrote.
That was also the reason why when you have mangle rules but forget to include conditions like dst-address-type=!local you won't be able to reach the router itself (for example for WinBox or DNS) if the mangle condition matches. Because mangle was processed before local.
The vrf flag was not originally designed to force traffic into a VRF. Instead, it was introduced by MikroTik to allow standard /routing rule entries to replicate the behavior of the built-in VRF lookup process.
Yes. The vrf flag is not an action (actions are drop / lookup / lookup-only-in-table / mangle / unreachable) so it does not force anything. It's a condition, same as the dst-address, src-address or interface matching conditions. The updated documentation under manual.mikrotik.com now has somewhat better wording for the default decision chains:
Look up the destination in the routing table marked by mangle rule.
If interface belongs to a VRF or packet was steered to a VRF, then try to lookup in the VRF table.
If VRF lookup fails reject the packet.
Check that the packet has to be locally delivered (the destination address is the address of the router).
process user defined routing rules (from "user" chain)
Look up the destination in the main routing table.
So, the vrf flag is a matching condition for: "the interface the packet is coming from belongs to a VRF or the packet was steered to a VRF", and we have the two invisible built-in rules that use the flag:
an invisible rule with action=lookup vrf chain=vrf-lookup: when that condition matches, perform look up in the routing table associated with the particular VRF (VRF of the interface or the one the packet was "steered to"), note that this rule does not need to mention table=xxx because the table information come from the associated VRF.
one with action=unreachable vrf chain=vrf-unreach: this rule has the same condition as the previous rule (same vrf flag), but if we reach this position, then it means that the lookup in the table of the previous rule has failed to find a suitable active route for the packet matching the vrf condition. We don't want the lookup to fall back to the main or local table, so this rule is placed here with an explicit unreachable action (which will stop further processing and send an ICMP message to the sender of the packet if applicable) to "reject the packet".