VyOSXXXIV · Route RedistributionRedistribution anti-patterns
Redistribution anti-patterns — bidirectional loops, missing tags, suboptimal paths
What you'll learn
- Recognise the four anti-patterns: bidirectional loops, missing route-maps, missing tags, suboptimal paths
- Diagnose each anti-pattern from the routing table and BGP/OSPF database evidence
- Apply the four remediations: tag-based feedback prevention, route-map filtering, administrative-distance tuning, redistribute-only-the-intended-prefixes
- Build a redistribution design that survives operational change
Prerequisites
- Ethernet, MAC and ARP — the Layer 2 the routing engineer must read
- Redistribution concept — why redistribute, route-map filtering, metric preservation, seed metric
- Redistributing static into BGP — route-map filtering, seed metric, community tags
- Redistributing OSPF into BGP — what survives the boundary, the MED, and feedback prevention
- Redistributing connected routes — physical interface routes, when to include, when to exclude
- Redistributing kernel routes — what `redistribute kernel` really carries, and why it is rarely the right answer
Verified against VyOS 1.5.x LTS (circinus) · VyOS 1.4.x (sagitta) — legacy · FRRouting 10.x (VyOS 1.5) · Linux kernel 6.6 LTS (VyOS 1.5 base) · strongSwan 5.9.x (IPsec) · WireGuard 1.0.x (kernel module + userspace tooling)
Redistribution is the source of the most common production routing failures: route leaks, suboptimal paths, and routing loops. The four anti-patterns are well-known but the operator who does not internalise them will encounter them in every multi-protocol network.
This lesson covers the four anti-patterns, their evidence, and their remediations. The pattern is consistent: every anti-pattern is a missing control, and every control is a tag, route-map, or administrative-distance tuning.
Anti-pattern 1: bidirectional redistribution loop
Two routers running OSPF and BGP, each redistributing the other protocol into its own, is the textbook loop. R1 redistributes OSPF into BGP; R2 redistributes BGP into OSPF; R1 sees its own route come back through OSPF as an external route.
flowchart LR
O1["10.10.0.0/16\nOSPF internal on R1, cost 50"]
R1["R1\nBGP AS 64512\nredistribute ospf into bgp"]
R2["R2\nBGP AS 64513\nredistribute bgp into ospf"]
O1 --> R1
R1 -- "eBGP UPDATE\n10.10.0.0/16, MED 50" --> R2
R2 -- "OSPF Type 5 LSA\n10.10.0.0/16, metric 100" --> O1
The evidence:
show ip ospf database external self-originateon R1 shows the redistributed-back route as Type 5.show ip bgpon R1 shows the route with R2’s community tag.- The metric oscillates as BGP refreshes.
The remediation: tag-based feedback prevention. R1 stamps a community tag on the OSPF-to-BGP redistribution; R2 denies the tag on the BGP-to-OSPF redistribution.
# On R1: stamp a unique community on what it redistributes
set policy route-map OSPF-TO-BGP rule 10 action 'permit'
set policy route-map OSPF-TO-BGP rule 10 set community add '64512:400'
set protocols bgp system-as 64512
set protocols bgp address-family ipv4-unicast redistribute ospf route-map 'OSPF-TO-BGP'
# On R2: classify R1's tag, then refuse to send it back into OSPF
set policy community-list FROM-R1 rule 10 action 'permit'
set policy community-list FROM-R1 rule 10 regex '64512:400'
set policy route-map BGP-FILTER rule 10 action 'deny'
set policy route-map BGP-FILTER rule 10 match community community-list 'FROM-R1'
set policy route-map BGP-FILTER rule 20 action 'permit'
set protocols ospf redistribute bgp route-map 'BGP-FILTER'
After the fix, R2 denies any BGP route carrying 64512:400.
R1’s redistributed routes are not re-injected into OSPF. The
loop is broken.
Three details in that configuration are 1.5-specific and each one breaks a 1.3-era runbook silently or loudly:
set community add '64512:400'. On 1.3 the clause was a single string with a trailing keyword —set community '64512:400 additive'. On 1.5addandreplaceare nodes in the tree, not words inside the value, and you must choose.addis what you want here:replacewould discard whatever communities the route already carried, including tags a different pair of routers is relying on.- The community-list rule’s value leaf is called
regex, notcommunity. It is one leaf and it is matched as a regular expression, which matters when you graduate from a single tag to64512:.*. - The route-map matches with
match community community-list 'FROM-R1'— the community-list is named through its own node, not passed as a bare argument.
And rule 20 is not optional. A route-map ends in an implicit
deny, so BGP-FILTER without the bare permit at rule 20 would
stop redistributing anything into OSPF at all — which looks,
from the routing table, exactly like the loop being fixed very
thoroughly.
Anti-pattern 2: missing route-map filter
The redistribution statement is configured without a route-map. Every route from the source protocol is redistributed. Internal prefixes leak.
# Anti-pattern: unfiltered redistribution
set protocols bgp system-as 64512
set protocols bgp address-family ipv4-unicast redistribute ospf
Note where redistribute lives on 1.5: under the
address-family, not directly under the BGP node. A redistribution
is a statement about one address family, and the tree says so.
The evidence:
show ip bgp neighbors <peer> advertised-routesshows internal prefixes (10.0.0.0/8, 192.168.0.0/16, etc.).- The upstream provider’s
received-routesshows the same prefixes.
The remediation: add a route-map that enumerates the prefixes the operator intends to redistribute.
# Fix: route-map with explicit prefix-list
set policy prefix-list ADVERTISE-OUT rule 10 action 'permit'
set policy prefix-list ADVERTISE-OUT rule 10 prefix '192.168.0.0/16'
set policy prefix-list ADVERTISE-OUT rule 10 le '24'
set policy route-map OSPF-TO-BGP rule 10 action 'permit'
set policy route-map OSPF-TO-BGP rule 10 match ip address prefix-list 'ADVERTISE-OUT'
set protocols bgp system-as 64512
set protocols bgp address-family ipv4-unicast redistribute ospf route-map 'OSPF-TO-BGP'
prefix, ge and le are three separate leaves under the
rule; they do not combine onto one set line. And there is no
closing action deny rule to add: a prefix matching no rule is
denied by the list, and a route matching no rule is denied by
the route-map. Both denies are structural, and a rule carrying
an action with no prefix under it is rejected at commit rather
than accepted as a catch-all.
The fix is straightforward but the leak may have already propagated. The operator must also notify the upstream provider to withdraw the leaked prefixes.
Anti-pattern 3: missing feedback-prevention tag
The redistribution has a route-map but no tag is stamped on the outbound direction. The downstream peer cannot filter based on the redistribution source; the loop is possible.
The evidence:
show ip bgp <prefix>shows the route has no community tag identifying the redistribution source.- The downstream peer’s
show ip bgp community <value>returns nothing for the redistribution source.
The remediation: stamp a community tag on the outbound redistribution.
# On R1: stamp the community tag
set policy route-map OSPF-TO-BGP rule 10 set community add '64512:400'
The tag is the contract. The downstream peer filters based on the tag.
add rather than replace, for the reason above: the route may
already be carrying tags that belong to somebody else’s control
loop, and replacing them removes a control you cannot see from
here.
Anti-pattern 4: suboptimal path from AD collision
When two protocols learn the same prefix, the AD decides which wins in the kernel FIB. A redistribution can create a situation where the wrong protocol wins.
The classic example is a redistribution feeding a prefix back to the router that already had it. R1 learns 10.10.0.0/16 by iBGP, which FRR gives an administrative distance of 200. R2 redistributes BGP into OSPF, so the same prefix arrives back at R1 as an OSPF external — and FRR gives OSPF an administrative distance of 110 whether the route is internal or external. 110 beats 200, so the FIB installs the OSPF external path.
Look at what that means. R1 is forwarding via a path it learned from a re-injection of its own BGP information, and the shorter BGP path it already had is sitting unused in the Loc-RIB. The routing is not wrong in the sense of being broken; it is wrong in the sense of being derived from a longer loop than the one the operator designed.
The evidence:
show ip route 10.10.0.0/16shows the OSPF external route as the selected path. FRR’s output marks the selected candidate and lists the others, so this one command shows both the winner and what it beat.vtysh -c 'show ip bgp 10.10.0.0/16'shows the iBGP path present and best within BGP — BGP chose it; zebra then preferred another protocol’s candidate.show ip ospf database external self-originateon R2 confirms R2 is the one originating the Type 5 LSA.
The remediation options, in order of preference:
- Do not redistribute the prefix back. If R1’s BGP already carries 10.10.0.0/16, R2 injecting it into OSPF adds nothing and creates the collision. A prefix-list on R2’s BGP-into-OSPF redistribution that excludes what BGP already distributes is the fix that removes the problem rather than outranking it.
- Raise the redistributed metric. Redistributing with a high metric keeps the external route as a genuine last resort. This helps only against other OSPF paths; it does nothing about the OSPF-versus-iBGP distance comparison, which is decided before metrics are considered.
- Tune the administrative distance.
set protocols ospf distance ospf external 210makes OSPF external routes less preferred than iBGP’s 200. Note the tree:distance ospf external, withospfas its own node —distance globalnext to it changes every OSPF route at once, which is almost never what you want here.
Diagnostic discipline
The four anti-patterns have overlapping symptoms but distinct evidence. The diagnostic discipline:
- Identify the winner and what it beat.
show ip route 10.10.0.0/16is FRR’s view: it lists every candidate for the prefix, from every protocol, and marks the one zebra selected. This is the command that shows the collision. - Confirm what the kernel actually holds.
ip route show 10.10.0.0/16is the kernel’s view, and it contains only the installed route. If FRR’s selected candidate and the kernel’s entry disagree, the problem is between zebra and the kernel, not between two protocols. - Identify the redistribution sources. There is no
per-protocol
show ... redistributeoperational command; read the configuration:show configuration commands | match redistributelists every redistribution statement on the router in one output, across BGP, OSPF and the rest. - Identify the route-maps.
vtysh -c 'show route-map'shows what FRR compiled, andshow configuration commands | match route-mapshows what you asked for. Read both; a name present in one and absent from the other is itself a finding. - Identify the tags.
show ip bgp community 64512:400lists the routes carrying a specific community, which tells you whether the feedback-prevention contract is being honoured in practice. - Walk the chain. For each redistribution, name the source, the route-map, the tag, and the destination. Write it down; the loop is usually obvious once the chain is on paper and invisible while it is spread across two routers.
flowchart TB
S1["OSPF internal\ncost 50 - distance 110"]
S2["OSPF external\nredistributed from BGP\nmetric 100 - distance 110"]
S3["iBGP\nMED 50 - distance 200"]
S1 --> D{"Step 1: lowest\nadministrative distance"}
S2 --> D
S3 --> D
D -- "110 beats 200" --> M{"Step 2: within OSPF,\nlowest cost"}
D -- "iBGP eliminated here,\nits MED never considered" --> X["iBGP path unused\nstill best inside BGP"]
M --> W1["OSPF internal installed"]
Read the two steps in order, because the order is the whole point. Distance is compared first and it is a comparison between protocols: iBGP at 200 loses to anything OSPF offers at 110, and it loses before its MED, its local-preference or its AS-path length are looked at. Only among the survivors — here, the two OSPF candidates, which share a distance — does a metric decide anything.
This is why “the BGP path was clearly better” is not an argument zebra will ever hear, and why the fix for a collision is to remove one of the candidates rather than to improve the one that is losing.
The four remediations
The four anti-patterns have four remediations:
- Loop → tag-based feedback prevention (community on outbound, deny on inbound).
- Missing filter → route-map with prefix-list enumeration on the redistribution.
- Missing tag → community stamping on the outbound redistribution.
- Suboptimal path → route-map filtering (preferred) or AD tuning (escape hatch).
Every redistribution in production should have:
- A route-map filter that enumerates the prefixes.
- A community tag on the outbound direction.
- A coordinated deny on the inbound direction at every peer that redistributes the other way.
The defensive design is symmetric: R1 stamps a tag; R2 denies the tag; R2 stamps a different tag; R1 denies R2’s tag. Both sides honour the contract; the loop is broken on both sides.
Operational commands
# FRR's view: every candidate for the prefix, winner marked
show ip route 10.10.0.0/16
# The kernel's view: only what is installed
ip route show 10.10.0.0/16
# Every redistribution statement on this router, in one output
show configuration commands | match redistribute
# The route-maps: what FRR compiled, and what you asked for
vtysh -c 'show route-map'
show configuration commands | match route-map
# The tags
show ip bgp community 64512:400
show ip bgp community 64512:500
# Walk the chain
show ip bgp neighbors 10.0.0.2 advertised-routes
show ip ospf database external self-originate
# Re-evaluate inbound policy without dropping the session
clear ip bgp 10.0.0.2 soft in
clear ip bgp 10.0.0.2 soft in asks the peer for a route
refresh and re-runs inbound policy against what comes back. The
session stays up throughout, which is what makes it safe to use
while you are still forming a hypothesis — the hard clear ip bgp 10.0.0.2 tears the session down and reconverges, and is
not a diagnostic.
There is no operational command that evicts one prefix to force a re-decision. Changing the inputs is what changes the outcome: fix the redistribution or the policy, and zebra re-evaluates.
Production discipline
Cross-course references
XXXIV-VyOS-Redistribution(the previous lessons in this part) covers each redistribution source (static, OSPF, connected, kernel) and their specific configuration patterns.XXV-VyOS-BGPAdvertisecovers redistribution in the BGP context.XXXIII-VyOS-RoutePolicycovers the route-map filtering primitives used here.XXVI-VyOS-BGPAttributescovers the MED attribute and the community attribute that are the building blocks of the redistribution design.
Quiz
Knowledge check · 4 questions
Q1. Which is the canonical remediation for a bidirectional redistribution loop?
Q2. An unfiltered `redistribute ospf` is a route leak.
Q3. R1 and R2 run OSPF area 0 and iBGP. R1 redistributes OSPF into BGP with metric 50. R2 redistributes the iBGP back into OSPF with metric 100. R1 sees its own OSPF route come back as Type 5 with metric 100. The MED in BGP oscillates between 50 and 100. What is the canonical remediation?
R1 and R2 run OSPF and iBGP. Both redistribute bidirectionally. The OSPF LSDB shows the route as Type 5 from R2. The BGP MED oscillates.
Q4. R1 learns 10.10.0.0/16 by iBGP. R2 redistributes BGP into OSPF, so R1 also learns the same prefix as an OSPF external. R1's `show ip route 10.10.0.0/16` selects the OSPF external path, and R1 now forwards using a re-injection of information it already had. Why does OSPF win, and what should be fixed?
R1 has an iBGP path to 10.10.0.0/16 and an OSPF external path for the same prefix, the latter produced by R2 redistributing BGP into OSPF. Zebra selects the OSPF external path.
Passing score: 75%. Answers are checked in this browser.