Introduction to Routing Policy and Configuration
Overview of RIB and FIB
The Routing Information Base (RIB) is the router’s logical table of all routes learned from routing protocols, static configuration, or policy injection. Each entry contains the destination prefix, next‑hop, administrative distance, metric, and associated attributes (e.g., BGP communities, OSPF tags).
The Forwarding Information Base (FIB) is a derived, optimized data structure used by the forwarding plane to make per‑packet lookup decisions. In most modern routers the FIB is a compressed trie or hash table built from the RIB; any discrepancy between the two means packets may be forwarded along a path that the control plane does not consider valid.
Declared Policy and Rendered Configuration
Declared policy is the intent expressed in the router’s configuration language (e.g., route‑map, policy‑statement, filter‑list). Rendered configuration is the actual set of configuration lines that the router has parsed, validated, and installed into its active config after a commit or write‑memory operation. Ideally, declared policy equals rendered configuration; however, syntax errors, conditional inheritance, or vendor‑specific defaults can cause a mismatch that is not immediately visible in the output of show running-config.
Understanding RIB and FIB Divergence
Causes of Divergence After Policy Changes
- Partial Commit or Failed Validation – A policy edit may be accepted syntactically but rejected during semantic validation (e.g., referencing an undefined prefix‑list). The router rolls back the offending lines, leaving the previously active policy in the rendered config while the RIB still reflects the old routes.
- Asynchronous RIB‑FIB Refresh – Some platforms update the RIB immediately after a policy re‑apply but defer FIB reconstruction to a background process or to the next scheduled poll. During this window the FIB may still contain stale entries.
- Route‑Redistribution Loops or Dampening – A policy change that alters redistribution metrics can cause a route to be withdrawn from the RIB, but the FIB may retain a forwarding entry if the route is still present in a local RIB copy used by the forwarding ASIC.
- Hardware‑Specific FIB Limits – TCAM exhaustion or hash‑collision handling can cause the FIB to drop a prefix silently while the RIB keeps it, especially after a large batch of policy‑driven prefix additions.
- Control‑Plane vs. Data‑Plane Software Versions – In routers that separate the control plane (e.g., a Linux‑based FRR instance) from the forwarding ASIC, a mismatch in the version of the routing daemon versus the firmware that programs the FIB can lead to divergence.
Impact of Divergence on Network Routing
- Black‑holing – Packets destined for a prefix that exists in the RIB but not in the FIB are dropped, causing intermittent loss that correlates with the timing of policy pushes.
- Micro‑loops – Stale FIB entries may point to a next‑hop that is no longer reachable, prompting the router to send traffic back toward the source, creating a transient loop until the FIB is refreshed.
- Sub‑optimal Path Selection – If the FIB retains an older, higher‑cost path while the RIB has converged to a better route, traffic experiences higher latency or jitter.
- Inconsistent Telemetry – Monitoring tools that query the RIB (e.g.,
show ip route) may report healthy convergence, while packet‑level probes (e.g., traceroute) observe loss, complicating root‑cause analysis.
Declared Policy and Rendered Configuration Matching
Policy Configuration Examples
Cisco IOS‑XR
route-policy BGP-IN
if destination in PFX-ALLOWED then
set local-preference 200
set community 65000:100 additive
else
drop
endif
end-policy
Juniper Junos
policy-options {
policy-statement BGP-IN {
term ALLOW {
from {
prefix-list PFX-ALLOWED;
}
then {
local-preference 200;
community add 65000:100;
accept;
}
}
term DENY {
then reject;
}
}
}
FRR (Linux)
route-map BGP-IN permit 10
match ip address prefix-list PFX-ALLOWED
set local-preference 200
set community 65000:100 additive
!
route-map BGP-IN deny 20
Rendered Configuration Examples
After committing the above, the rendered config (as seen with show running-config | include route-policy|policy-options|route-map) should contain the exact same lines, assuming no syntax errors. Example output from IOS‑XR:
RP/0/RP0/CPU0:router# show running-config | include route-policy
route-policy BGP-IN
if destination in PFX-ALLOWED then
set local-preference 200
set community 65000:100 additive
else
drop
endif
end-policy
If the prefix‑list PFX-ALLOWED is missing, the commit will fail and the rendered config will not contain the new route-policy; the old policy remains active.
CLI Commands for Policy and Configuration Verification
| Platform | Verify Declared Intent | Verify Rendered Config |
|---|---|---|
| Cisco IOS‑XR | show running-config route-policy BGP-IN | `show running-config |
| Juniper Junos | show configuration policy-options policy-statement BGP-IN | `show configuration |
| FRR | show route-map BGP-IN | `show running-config |
| Linux (iproute2) | nft list table ip filter (if using nftables) | nft list ruleset |
A match between the declared intent block and the rendered config lines confirms that the policy has been successfully loaded into the active configuration.
Comparison Chain for Detecting Divergence
Step‑by‑Step Comparison Process
- Declare → Rendered – Verify that the policy text in the committed config matches the source of truth (e.g., Git repo, CI‑generated snippet). Any mismatch indicates a commit failure or partial apply.
- Rendered → RIB – Extract the effective policy from the rendered config (via parser or native
showcommand) and simulate its effect on the RIB (or directly compare the RIB to the expected routes derived from the policy). Tools:show ip route,show route,show ip bgp. - RIB → FIB – Compare each RIB entry’s next‑hop and outgoing interface to the corresponding FIB entry. Discrepancies indicate a failure in the RIB‑to‑FIB sync process.
- FIB → Data‑Plane (optional) – Validate hardware counters or packet‑traces to confirm that the FIB entry is actually being used for forwarding.
If steps 1 and 2 pass but step 3 fails, the root cause lies in the RIB‑FIB synchronization layer, not in the policy itself.
Example Comparison Chain Scenarios
Scenario A – Policy Accepted, RIB Updated, FIB Stale
- Declared policy:
set local-preference 200 for PFX-ALLOWED. - Rendered config matches declared policy (verified via
show running-config). - RIB shows the prefix with local‑preference 200 and next‑hop 10.0.0.2.
- FIB still shows the prefix with local‑preference 100 and next‑hop 10.0.0.1 (old policy).
→ Divergence detected at step 3.
Scenario B – Policy Rejected, Rendered Config Unchanged
- Declared policy references missing prefix‑list
PFX-ALLOWED. - Commit fails; rendered config retains old policy (no new
route-policylines). - RIB still reflects old policy (no change).
- FIB matches RIB (both old).
→ Divergence detected at step 1 (declared ≠ rendered).
Scenario C – Hardware TCAM Exhaustion
- Declared and rendered policies both add 100k new prefixes.
- RIB receives all 100k prefixes (verified via
show ip route | count). - FIB shows only 90k entries; the missing 10k are silently dropped.
→ Divergence detected at step 3 despite correct policy and RIB.
Code Examples for Automating Comparison
Below is a Python snippet using Napalm to fetch rendered config, RIB, and FIB, then compare them. The example assumes Cisco IOS‑XR but can be adapted.
#!/usr/bin/env python3
import json
from napalm import get_network_driver
def fetch_data(device):
driver = get_network_driver('iosxr')
with driver(hostname=device['host'],
username=device['user'],
password=device['pwd']) as dev:
# 1. Rendered config (as structured object)
rendered = dev.get_config()['running']
# 2. RIB (routing table)
rib = dev.get_route_to('0.0.0.0/0') # returns dict of all routes
# 3. FIB (CEF table on IOS‑XR)
fib = dev.get_fib() # vendor‑specific; returns list of FIB entries
return rendered, rib, fib
def compare_policy(rendered_cfg, expected_policy):
# Simple string containment; in production use a proper parser (e.g., CiscoConfParse)
return expected_policy in rendered_cfg
def compare_rib_fib(rib, fib):
# Build a set of (prefix, next-hop) from RIB
rib_set = {(entry['prefix'], entry['next_hop']) for entry in rib.values()}
# Build same set from FIB (adjust keys per vendor)
fib_set = {(f['prefix'], f['next_hop']) for f in fib}
missing_in_fib = rib_set - fib_set
extra_in_fib = fib_set - rib_set
return missing_in_fib, extra_in_fib
if __name__ == '__main__':
device = dict(host='router1.example.com', user='admin', pwd='secret')
expected_policy = "route-policy BGP-IN" # from source of truth
rendered, rib, fib = fetch_data(device)
# Step 1: Declared vs Rendered
if not compare_policy(rendered, expected_policy):
print("❌ Declared policy does NOT match rendered config")
else:
print("✅ Declared policy matches rendered config")
# Step 3: RIB vs FIB
missing, extra = compare_rib_fib(rib, fib)
if missing:
print(f"❌ RIB→FIB divergence: {len(missing)} prefixes missing in FIB")
for p, nh in list(missing)[:5]:
print(f" {p} via {nh}")
else:
print("✅ RIB and FIB are consistent")
if extra:
print(f"⚠️ FIB contains {len(extra)} entries not present in RIB (possible stale hardware entries)")
The script prints a clear pass/fail for each link in the chain, enabling automated alerting when the RIB‑FIB link breaks while the policy‑config link stays intact.
Troubleshooting RIB and FIB Divergence
Identifying Divergence Using CLI Commands
| Platform | Check RIB | Check FIB | Typical Divergence Symptom |
|---|---|---|---|
| Cisco IOS‑XR | show route ipv4 unicast show bgp ipv4 unicast | show cef ipv4 prefix <x.x.x.x/len> detail show cef ipv4 drops | show route shows a prefix, but show cef returns “%CEF: No entry found” or shows an older next‑hop. |
| Juniper Junos | show route show bgp neighbor <ip> received-routes | show route forwarding-table destination <x.x.x.x/len> show route forwarding-table match <x.x.x.x/len> | Forwarding table lacks the entry or shows a different next‑hop. |
| FRR | show ip route show bgp ipv4 unicast | show ip fib (if FRR compiled with FIB support) dpctl dump flows (OVS) | show ip route lists a prefix; show ip fib returns “No such entry”. |
| Linux (kernel) | ip route show table main | ip -d route show table <tid> or cat /proc/net/fib_trie | Kernel FIB missing routes that appear in ip route. |
Procedure
- Identify the suspect prefix (e.g., from user complaint or monitoring alert).
- Run the RIB command to confirm the prefix exists and note its attributes (next‑hop, metric, local‑pref).
- Run the FIB command for the same prefix; compare next‑hop, outgoing interface, and any encapsulation labels.
- If they differ, check the FIB sync logs:
show logging | include fib(IOS‑XR),show system processes detail | match fib(Junos), ordmesg | grep -i fib(Linux).
Analyzing Logs and System Messages
- IOS‑XR:
%ROUTING-FIB-5-REBUILDindicates a FIB rebuild;%ROUTING-FIB-3-ADJ_FAILsignals adjacency problems that can stall FIB updates. - Junos:
kernel: rtalloc: dst 0.0.0.0/0: fib_lookup failedappears in/var/log/messageswhen the forwarding table cannot resolve a route. - FRR:
zebra: FIB update failed: No such deviceindicates a missing interface in the kernel FIB. - Linux kernel:
net_ratelimit: N callbacks suppressedmay hide repeated FIB allocation failures; increasenet.core.netdev_max_backlogor checkkmemleak.
Look for timestamps that align with the policy change commit. A gap between the commit timestamp and the first FIB‑error log often points to asynchronous FIB reconstruction.
Common Issues and Solutions
| Issue | Likely Cause | Remedy |
|---|---|---|
| FIB missing prefixes after large policy push | TCAM exhaustion or hash collision | Increase TCAM allocation, summarize routes, or enable FIB compression if supported. |
| Stale next‑hop in FIB after route‑map change | Asynchronous FIB refresh | Force a FIB rebuild (clear cef ipv4 on IOS‑XR, restart routing on Junos) or wait for the background refresh interval. |
| Policy commit fails silently | Undefined referenced object (prefix‑list, community‑set) | Validate all referenced objects before commit; use commit check or equivalent. |
| FIB shows extra entries not in RIB | Hardware aging or stale ASIC cache | Clear FIB (clear ip fib on FRR, clear route forwarding-table on Junos) and monitor for re‑population. |
| Divergence only on specific line cards | Line‑card firmware mismatch | Upgrade line‑card firmware to match control‑plane version; verify compatibility matrix. |
By following the comparison chain and using the CLI/log‑based checks above, operators can quickly isolate whether a policy‑configuration mismatch or a RIB‑FIB synchronization problem is responsible for observed forwarding anomalies.