ip rule and Multiple Routing Tables: Practical Troubleshooting GuideMost Linux systems can route traffic perfectly well with one routing table.
Then you add a second network interface.
Or a second Internet connection.
Or a management network.
Or a VPN.
Suddenly, the ordinary destination-based routing model is no longer enough.
You may need traffic from one source address to use Gateway A while traffic from another address uses Gateway B. A management subnet may need its own path. Packets marked by nftables may need a dedicated gateway. A transparent proxy may require special local routes. Or a multi-homed server may need replies to leave through the same network path on which connections arrived.
This is where Linux policy routing becomes essential.
Instead of asking only:
Where is this packet going?
Linux can make routing decisions using additional information such as the packet’s source address, incoming interface, firewall mark, and other selectors.
The two commands at the center of this architecture are:
ip rule and:
ip route Understanding how they interact is one of the most valuable skills in advanced Linux networking.
This guide explains Linux’s Routing Policy Database, multiple routing tables, rule priorities, source-based routing, fwmark routing, ip route get, common configuration mistakes, and a practical end-to-end troubleshooting workflow.
Traditional routing is primarily destination based.
Suppose Linux receives a packet destined for:
8.8.8.8 The system looks for the most appropriate route toward that destination.
A simple table might contain:
default via 192.168.1.1 dev enp1s0
192.168.1.0/24 dev enp1s0 The answer is straightforward:
8.8.8.8
↓
default route
↓
192.168.1.1
↓
enp1s0 But what if the server has two Internet connections?
ISP A ISP B
| |
Gateway A Gateway B
| |
enp1s0 enp2s0
\ /
\ /
Linux Server Suppose the addresses are:
enp1s0 = 192.168.10.20
enp2s0 = 10.20.30.20 You want:
Traffic from 192.168.10.20
↓
Gateway A while:
Traffic from 10.20.30.20
↓
Gateway B A single ordinary default route does not adequately express that requirement.
You need a routing policy.
Linux provides this through the Routing Policy Database, commonly inspected with:
ip rule The ip utility exposes rule as a dedicated object alongside route, address, link, neighbor, netns, vrf, and other networking objects.
If your immediate problem is simply that packets are leaving through an unexpected NIC, start with CorgiNetwork’s <a href=”https://corginetwork.com/linux-traffic-uses-wrong-interface/“>Linux Traffic Uses the Wrong Interface: Complete Troubleshooting Guide</a>. It provides the diagnostic foundation before you redesign the routing policy.
Run:
ip route On many systems you might see:
default via 192.168.10.1 dev enp1s0
192.168.10.0/24 dev enp1s0
10.20.30.0/24 dev enp2s0 This normally displays routes from the main routing table.
According to the current ip-route(8) documentation, Linux supports multiple routing tables identified numerically—or by configured names—and ordinary routes normally go into the main table, whose ID is:
254 Linux also maintains a special local table:
255 for local and broadcast addresses. Multiple routing tables become particularly important when policy routing is used.
This means:
ip route does not necessarily describe your entire routing architecture.
Use:
ip route show table all when troubleshooting a policy-routed system.
Linux reserves several table IDs.
The most important ones for everyday troubleshooting include:
255 → local
254 → main
253 → default The local table is automatically maintained by the kernel and contains routes associated with local and broadcast addresses. Administrators normally do not manually modify it.
You can inspect it:
ip route show table local Then inspect the main table:
ip route show table main Compare that with:
ip route show table all The difference becomes important once custom tables appear.
Suppose we want two independent routing domains:
Table 100 → ISP A
Table 200 → ISP B Linux routing tables can be addressed directly by number:
ip route show table 100 and:
ip route show table 200 You can therefore build a structure such as:
TABLE 100
192.168.10.0/24 dev enp1s0
default via 192.168.10.1 dev enp1s0 and:
TABLE 200
10.20.30.0/24 dev enp2s0
default via 10.20.30.1 dev enp2s0 The routing tables themselves do not answer one crucial question:
Which packets should use Table 100, and which should use Table 200?
That is the job of:
ip rule Run:
ip rule show A simple system may return something similar to:
0: from all lookup local
32766: from all lookup main
32767: from all lookup default Read the rules conceptually from higher priority toward lower priority.
A lower numeric priority is processed earlier.
So:
0 has higher priority than:
1000 which has higher priority than:
32766 This detail is critical.
Administrators sometimes assume a larger number means a more important rule.
For ip rule, think:
smaller number
↓
checked earlier Suppose traffic sourced from:
192.168.10.20 should use:
table 100 The conceptual rule is:
ip rule add from 192.168.10.20/32 table 100 priority 100 For the second address:
ip rule add from 10.20.30.20/32 table 200 priority 200 Now:
ip rule might show:
0: from all lookup local
100: from 192.168.10.20 lookup 100
200: from 10.20.30.20 lookup 200
32766: from all lookup main
32767: from all lookup default Conceptually:
Packet source
|
+── 192.168.10.20
| ↓
| Table 100
|
+── 10.20.30.20
↓
Table 200 This is source-based policy routing.
For a simplified example:
ip route add 192.168.10.0/24 dev enp1s0 \
src 192.168.10.20 table 100 Then:
ip route add default via 192.168.10.1 \
dev enp1s0 table 100 Inspect it:
ip route show table 100 Expected conceptually:
192.168.10.0/24 dev enp1s0 src 192.168.10.20
default via 192.168.10.1 dev enp1s0 Now:
ip route add 10.20.30.0/24 dev enp2s0 \
src 10.20.30.20 table 200 Then:
ip route add default via 10.20.30.1 \
dev enp2s0 table 200 Inspect:
ip route show table 200 Expected:
10.20.30.0/24 dev enp2s0 src 10.20.30.20
default via 10.20.30.1 dev enp2s0 We now have:
192.168.10.20
↓
Rule 100
↓
Table 100
↓
enp1s0
10.20.30.20
↓
Rule 200
↓
Table 200
↓
enp2s0 This is far more deterministic than simply installing two competing default routes in the main table.
For an Ubuntu/Netplan implementation of this architecture, see CorgiNetwork’s <a href=”https://corginetwork.com/netplan-multiple-default-routes-policy-routing/“>Netplan Multiple Default Routes and Policy Routing Guide</a>.
One of the most common mistakes is creating only:
default via 192.168.10.1 inside the custom table.
You also need the routing table to understand how to reach the gateway itself.
For example:
192.168.10.0/24 dev enp1s0 before:
default via 192.168.10.1 dev enp1s0 Otherwise you can encounter errors or unexpected gateway resolution behavior.
Think of each custom routing table as needing enough information to make its own forwarding decisions.
ip route getNever assume the policy works because:
ip rule looks correct.
Ask the kernel.
Run:
ip route get 8.8.8.8 from 192.168.10.20 You should expect a result consistent with:
via 192.168.10.1 dev enp1s0 Now test the second source:
ip route get 8.8.8.8 from 10.20.30.20 Expected:
via 10.20.30.1 dev enp2s0 The current ip-route(8) interface supports route lookup parameters including source address, incoming interface, outgoing interface, mark, protocol, source port, and destination port.
That makes ip route get considerably more useful than simply staring at routing-table entries.
ip route get vs ip routeThe difference is fundamental.
ip route asks:
What routes are in this table?
While:
ip route get 8.8.8.8 from 10.20.30.20 asks something much closer to:
How would Linux resolve this specific route lookup with these properties?
For troubleshooting, the second question is usually more valuable.
ip route Can Look Correct While Traffic Is WrongSuppose:
ip route returns:
default via 192.168.10.1 dev enp1s0 You conclude:
Everything uses enp1s0.
But:
ip rule contains:
200: from 10.20.30.20 lookup 200 and:
ip route show table 200 contains:
default via 10.20.30.1 dev enp2s0 Then traffic sourced from:
10.20.30.20 may use the second routing table instead.
This is why CorgiNetwork’s <a href=”https://corginetwork.com/linux-traffic-uses-wrong-interface/“>Linux Wrong Interface troubleshooting guide</a> emphasizes checking:
ip rule
ip route show table all
ip route get DESTINATION from SOURCE rather than relying on the main table alone.
Consider:
100: from 10.20.30.20 lookup 100
200: from 10.20.30.20 lookup 200 Both rules match the same source.
Which one is considered first?
priority 100 because it has the smaller numeric value.
This can create extremely confusing failures when old rules remain after testing.
Always inspect:
ip rule before adding another rule.
Do not keep adding policies until connectivity happens to work.
A system that has been repeatedly modified may contain:
100: from 10.20.30.20 lookup 100
101: from 10.20.30.20 lookup 100
102: from 10.20.30.20 lookup 200 At that point, stop.
Document the intended architecture.
Then determine:
Which source?
Which table?
Which gateway?
Which interface?
Which priority? A clean policy is easier to troubleshoot than ten overlapping rules.
Rules do not have to match only a single /32 address.
For example:
ip rule add from 10.10.20.0/24 table 200 priority 200 Conceptually:
Any packet sourced from
10.10.20.0/24
↓
Table 200 This can be useful on routers and gateways.
But remember that a broader selector can match much more traffic than intended.
Use the narrowest policy that accurately represents the architecture.
Policies can also distinguish destinations.
For example, an architecture might require traffic toward a particular network to use a dedicated table.
Conceptually:
Destination 172.16.50.0/24
↓
Table 300 But before adding policy rules, ask whether an ordinary destination route in the main table would solve the problem more simply.
Do not use policy routing when normal routing already expresses the requirement clearly.
Linux policy rules can also involve an incoming interface.
This becomes useful on routers, gateways and more complex multi-homed systems.
The route lookup interface itself supports iif as one of the lookup properties, and Linux’s route Netlink interface exposes both incoming and outgoing interface attributes.
This allows architectures where:
Traffic entering Interface A
↓
Table A while:
Traffic entering Interface B
↓
Table B However, source-based rules are often easier to reason about for multi-address servers.
Choose selectors according to the actual network design.
Linux can also route based on a packet mark.
Conceptually:
Packet
↓
nftables assigns mark 10
↓
ip rule sees fwmark 10
↓
Table 100
↓
Gateway A A rule can look conceptually like:
ip rule add fwmark 10 table 100 priority 100 The Linux kernel’s transparent proxy documentation provides a real example of this model:
fwmark
↓
policy rule
↓
dedicated routing table and uses a marked rule with a separate table to deliver intercepted traffic locally.
This technique is useful for advanced use cases including:
Do not introduce packet marking if source- or destination-based routing already solves the problem.
Imagine that:
Browser traffic
↓
ISP A
Backup traffic
↓
ISP B Both types of traffic originate from the same IP address.
Source-based routing cannot distinguish them.
But a firewall can classify packets according to relevant characteristics and assign marks.
Then policy routing can map those marks to different tables.
Conceptually:
Traffic classification
↓
mark
↓
ip rule
↓
routing table
↓
gateway This separates classification from routing.
Suppose:
default via Gateway A metric 100
default via Gateway B metric 500 This can make sense when the requirement is:
Primary gateway
+
Backup gateway But if your requirement is:
Source A → Gateway A
Source B → Gateway B metrics alone do not describe the desired behavior.
That is a policy-routing problem.
Use CorgiNetwork’s <a href=”https://corginetwork.com/netplan-multiple-default-routes-policy-routing/“>Netplan Multiple Default Routes guide</a> for the Ubuntu-specific persistent implementation.
Consider:
Client
↓
Gateway B
↓
enp2s0
↓
Linux If Linux responds through:
enp1s0
↓
Gateway A the forward and return paths differ.
This is asymmetric routing.
Policy routing can often establish a more deterministic return path:
Traffic associated with Source B
↓
Table B
↓
Gateway B This becomes especially important when:
rp_filterPolicy routing and reverse-path filtering are closely related in multi-homed systems.
Suppose a packet arrives through:
enp2s0 but the reverse route toward the sender points through:
enp1s0 Strict reverse-path filtering can reject that packet.
The Linux kernel documentation defines strict rp_filter=1 as testing an incoming packet against the FIB and failing the check if the incoming interface is not the best reverse path. Loose mode 2 instead tests whether the source is reachable through any interface.
Before weakening reverse-path validation, verify whether policy routing should correct the route.
CorgiNetwork’s <a href=”https://corginetwork.com/linux-rp-filter-asymmetric-routing/“>Linux rp_filter and Asymmetric Routing Guide</a> covers this problem in detail.
Policy routing can also interact with ARP behavior.
Consider two NICs on the same subnet:
enp1s0 → 192.168.50.10
enp2s0 → 192.168.50.20 You may want each address to remain associated with its intended interface.
Linux ARP behavior does not automatically enforce that simple mental model.
In advanced configurations, routing decisions and ARP filtering need to agree.
If neighboring systems learn an unexpected MAC address for one of your IPs, see CorgiNetwork’s <a href=”https://corginetwork.com/linux-arp-flux-multiple-nics-same-subnetpolicy-routing/“>Linux ARP Flux: Multiple NICs on the Same Subnet</a> guide.
This gives our troubleshooting chain:
ARP behavior
↓
Incoming interface
↓
Policy rule
↓
Routing table
↓
Gateway
↓
Reverse-path validation Policy routing does not mean the main table becomes irrelevant.
Suppose your custom rule matches only:
from 10.20.30.20 Other traffic may eventually fall through to:
lookup main Therefore:
ip route remains important.
The correct mental model is not:
Policy routing replaces normal routing but rather:
Policy rules determine
which routing lookup applies The main table is still one possible lookup target.
Suppose:
100: from 192.168.10.20 lookup 100
200: from 10.20.30.20 lookup 200
32766: from all lookup main A packet sourced from:
172.16.10.50 matches neither rule 100 nor rule 200.
Processing continues until another rule applies.
Eventually:
from all lookup main can match.
This fall-through behavior is why rule order is so important.
Another subtle point: selecting a routing table does not automatically guarantee that table can resolve every destination.
Suppose:
Rule 100
↓
Table 100 but Table 100 contains only:
192.168.10.0/24 dev enp1s0 with no default route.
A lookup for:
8.8.8.8 cannot be satisfied by that route alone.
Policy-routing troubleshooting therefore requires examining both:
RULE and:
TABLE CONTENT Never inspect one without the other.
throw Routes: An Advanced Policy-Routing ToolLinux supports a special route type called:
throw The current ip-route(8) documentation describes a throw route as terminating lookup in that table as though no usable route were found, allowing policy-routing behavior to continue appropriately.
This is an advanced tool and usually unnecessary for basic two-NIC source routing.
But it demonstrates an important concept:
routing tables are part of a larger rule-driven lookup process.
They are not isolated static lists.
Numeric IDs work perfectly:
ip route show table 100 But administrators may prefer readable names.
Depending on the system, routing-table names can be defined through the iproute2 routing-table configuration files. The current manual documents table names via:
/usr/lib/iproute2/rt_tables or:
/etc/iproute2/rt_tables with the latter taking precedence when present.
Conceptually:
100 isp_a
200 isp_b Then commands become easier to read:
ip route show table isp_a and:
ip route show table isp_b Readable naming can significantly improve production troubleshooting.
Assume:
NIC A
Interface: enp1s0
Address: 192.168.10.20/24
Gateway: 192.168.10.1
Table: 100
NIC B
Interface: enp2s0
Address: 10.20.30.20/24
Gateway: 10.20.30.1
Table: 200 Desired behavior:
192.168.10.20
↓
enp1s0
↓
192.168.10.1
10.20.30.20
↓
enp2s0
↓
10.20.30.1 Runtime demonstration:
ip route add 192.168.10.0/24 \
dev enp1s0 src 192.168.10.20 table 100 ip route add default \
via 192.168.10.1 dev enp1s0 table 100 Then:
ip route add 10.20.30.0/24 \
dev enp2s0 src 10.20.30.20 table 200 ip route add default \
via 10.20.30.1 dev enp2s0 table 200 Add the policies:
ip rule add from 192.168.10.20/32 \
table 100 priority 100 ip rule add from 10.20.30.20/32 \
table 200 priority 200 Then verify everything.
Run:
ip rule Look for:
100: from 192.168.10.20 lookup 100
200: from 10.20.30.20 lookup 200 Do not proceed merely because the commands returned no error.
ip route show table 100 Expected conceptually:
192.168.10.0/24 dev enp1s0 src 192.168.10.20
default via 192.168.10.1 dev enp1s0 ip route show table 200 Expected:
10.20.30.0/24 dev enp2s0 src 10.20.30.20
default via 10.20.30.1 dev enp2s0 Test path A:
ip route get 8.8.8.8 from 192.168.10.20 Test path B:
ip route get 8.8.8.8 from 10.20.30.20 This is where configuration becomes evidence.
If both return the same interface, something is wrong with:
rule matching
table contents
priority
source selection A route lookup is essential, but the application path should also be tested.
For example:
curl --interface 192.168.10.20 https://example.com/ Then:
curl --interface 10.20.30.20 https://example.com/ You can also test basic connectivity:
ping -I 192.168.10.20 8.8.8.8 and:
ping -I 10.20.30.20 8.8.8.8 Remember that successful ICMP does not prove every TCP application will work.
Capture interface A:
sudo tcpdump -ni enp1s0 host 8.8.8.8 Capture interface B:
sudo tcpdump -ni enp2s0 host 8.8.8.8 Then generate traffic from each source.
This lets you verify:
Source A → Interface A
Source B → Interface B rather than assuming the rules behave as intended.
For deeper packet inspection, CorgiNetwork’s <a href=”https://corginetwork.com/wireshark-explained/“>Wireshark Explained</a> guide provides the packet-analysis layer of this troubleshooting workflow.
Administrators sometimes configure:
default via Gateway A metric 100
default via Gateway B metric 200 and expect:
Source A → Gateway A
Source B → Gateway B That is not what route metrics express.
Metrics primarily provide preference between routes.
If the decision depends on source identity, use policy routing.
Suppose:
100: from all lookup main
200: from 10.20.30.20 lookup 200 The broad rule may be encountered before the specific policy you intended.
Always inspect the entire RPDB:
ip rule and ask:
Which rule matches first? Do not look only for whether your custom rule exists.
This:
ip rule add from 10.20.30.20 table 200 does not magically populate:
table 200 Inspect:
ip route show table 200 A rule chooses a table.
The table still needs useful routes.
The opposite also occurs.
You create:
Table 200
default via 10.20.30.1 but no rule directs relevant traffic there.
The table exists but may never be selected for the traffic you intended.
Again:
RULE
↓
TABLE
↓
ROUTE All three matter.
A table with:
default via 10.20.30.1 needs a coherent way to reach:
10.20.30.1 Do not forget the directly connected subnet route where required.
ip routeIf policy routing exists, this is insufficient:
ip route Use:
ip rule plus:
ip route show table all plus:
ip route get DESTINATION from SOURCE Those three commands together reveal far more about the actual decision process.
rp_filter to Hide a Bad RouteSuppose strict reverse-path filtering rejects traffic because your return route points through the wrong NIC.
You disable it:
rp_filter = 0 and traffic starts working.
That does not necessarily mean disabling source validation was the best solution.
You may simply have allowed an inconsistent routing architecture to continue operating.
First examine the policy routing.
For the complete distinction between strict, loose and disabled reverse-path validation, use CorgiNetwork’s <a href=”https://corginetwork.com/linux-rp-filter-asymmetric-routing/“>Linux rp_filter Explained</a> guide.
Routing changes can disconnect your SSH session instantly.
This is especially dangerous when changing:
default routes
ip rules
management interfaces
policy priorities Before modifying a remote production server, have:
A technically correct policy is not useful if you lose access halfway through deploying it.
Commands such as:
ip rule add ... and:
ip route add ... table 100 are excellent for understanding and controlled runtime testing.
They are not automatically a persistent configuration strategy.
Persistent implementation depends on the distribution and network manager:
Netplan
NetworkManager
systemd-networkd
distribution-specific network configuration For Ubuntu systems using Netplan, continue with CorgiNetwork’s <a href=”https://corginetwork.com/netplan-multiple-default-routes-policy-routing/“>Netplan Policy Routing Guide</a> after you understand the underlying Linux behavior.
This article deliberately focuses on how the Linux routing engine works, while the Netplan article covers persistent Ubuntu configuration.
That separation also avoids keyword cannibalization between the two pages.
As networks become more complex, manually maintaining many source-based policy rules may not always be the cleanest architecture.
Linux also supports Virtual Routing and Forwarding (VRF).
The kernel documentation explains that a VRF device combined with ip rule can create separate Layer-3 routing domains, each with its own routing table. One documented use case is multi-tenancy where different tenants require separate routing tables and different default gateways.
Conceptually:
VRF BLUE
↓
Table 100
↓
Gateway A
VRF RED
↓
Table 200
↓
Gateway B VRF deserves its own article because it represents a broader architectural approach rather than merely another ip rule.
When policy routing behaves unexpectedly, use this sequence.
ip -br link ip -br addr ip route ip rule ip route show table all ip route show table 100
ip route show table 200 ip route get DESTINATION from SOURCE_A ip route get DESTINATION from SOURCE_B sysctl -a 2>/dev/null | grep '\.rp_filter' ip neigh sudo tcpdump -ni any host DESTINATION curl --interface SOURCE_IP https://example.com/ or for a TCP service:
nc -vz DESTINATION PORT This sequence moves from configuration to actual packet behavior.
Traffic uses wrong path
|
v
ip rule
|
v
Which rule matches first?
|
+----+----+
| |
Wrong Correct
| |
v v
Fix rule Inspect selected table
priority |
v
Does table contain
correct route?
|
+----+----+
| |
NO YES
| |
v v
Fix table ip route get
|
v
Correct interface?
|
+----+----+
| |
NO YES
| |
v v
Recheck rule Capture
selectors packets
|
v
Check rp_filter,
firewall and
upstream path On production servers, document the design in a simple matrix.
For example:
| Source | Interface | Gateway | Table | Rule Priority |
|---|---|---|---|---|
192.168.10.20 | enp1s0 | 192.168.10.1 | 100 | 100 |
10.20.30.20 | enp2s0 | 10.20.30.1 | 200 | 200 |
This simple table can save hours of troubleshooting later.
When you see:
priority 200 → table 200 you immediately know why it exists.
Before declaring policy routing complete, verify:
✓ Interfaces have expected addresses
✓ Connected routes exist
✓ Every custom table contains expected routes
✓ Every rule references the intended table
✓ Rule priorities are intentional
✓ Source-specific lookups choose correct interfaces
✓ Gateways are reachable
✓ ARP/neighbor resolution works
✓ rp_filter behavior is understood
✓ Firewall permits expected traffic
✓ Real packets use intended interfaces
✓ Configuration survives reboot
✓ Remote-management path remains reachable
✓ Routing design is documented Do not stop at:
ip rule looks correct The packet path is the final test.
Linux policy routing allows route selection to be influenced by policies beyond a simple destination lookup. Rules can direct traffic toward different routing tables according to properties such as source addresses and other supported selectors.
ip rule do?ip rule manages the Routing Policy Database used to determine which routing lookup should be applied to matching traffic.
Run:
ip rule show or simply:
ip rule Run:
ip route show table all The ip-route(8) documentation supports table all for listing routes across routing tables.
The main table has ID:
254 Normal routes are typically inserted there unless another table is explicitly selected.
Table 255 is the local table.
The kernel maintains it automatically for local and broadcast routes, and administrators generally do not need to modify it.
Yes.
Multiple defaults can exist in the same or different routing tables. The correct architecture depends on whether you need preference/failover, source-specific routing, ECMP, or another routing model.
Metrics express preference among applicable routes.
Policy routing allows different traffic to be directed to different routing tables according to matching rules.
A common architecture uses:
source address
↓
ip rule
↓
custom routing table
↓
specific gateway The exact persistent implementation depends on your Linux networking stack.
Use:
ip route get DESTINATION from SOURCE For example:
ip route get 8.8.8.8 from 10.20.30.20 The route-get interface supports source and several other lookup parameters.
ip route show all routing tables?Not by default.
Use:
ip route show table all when investigating policy routing.
A common reason is that no matching ip rule directs the relevant traffic toward that table.
Check:
ip rule and verify rule priority.
ip rule exist but traffic still fails?Inspect the selected routing table:
ip route show table TABLE_ID The table may lack a connected route, default route, or another route required to reach the destination.
Yes, especially in multi-homed and asymmetric-routing configurations. Strict reverse-path validation evaluates incoming traffic against routing information, so inconsistent return paths can cause packet drops. The Linux kernel documents strict and loose reverse-path modes explicitly.
Yes.
A packet mark can be used by policy rules to direct marked traffic into a dedicated routing table. Linux’s kernel documentation demonstrates this pattern for transparent proxy routing.
Linux policy routing becomes essential when one routing table can no longer describe how traffic should move through a system.
The core model is simple:
PACKET
↓
POLICY RULE
↓
ROUTING TABLE
↓
ROUTE
↓
GATEWAY / INTERFACE For a two-NIC server, that can become:
Source A
↓
Rule A
↓
Table A
↓
Gateway A
Source B
↓
Rule B
↓
Table B
↓
Gateway B The commands you should remember are:
ip rule
ip route
ip route show table all
ip route show table TABLE_ID
ip route get DESTINATION from SOURCE But the most important lesson is not to add rules blindly.
When Linux uses an unexpected path, determine which rule matched, which table was selected, which route that table returned, and what the real packets did afterward.
If Linux is choosing the wrong NIC, continue with CorgiNetwork’s <a href=”https://corginetwork.com/linux-traffic-uses-wrong-interface/“>Linux Traffic Uses the Wrong Interface</a>.
For persistent Ubuntu source routing, use <a href=”https://corginetwork.com/netplan-multiple-default-routes-policy-routing/“>Netplan Multiple Default Routes and Policy Routing</a>.
If incoming packets disappear because the return path differs, use <a href=”https://corginetwork.com/linux-rp-filter-asymmetric-routing/“>Linux rp_filter and Asymmetric Routing</a>.
And when multiple interfaces occupy the same subnet and neighboring hosts learn unexpected MAC mappings, continue with <a href=”https://corginetwork.com/linux-arp-flux-multiple-nics-same-subnetpolicy-routing/“>Linux ARP Flux and Multiple NICs on the Same Subnet</a>.
These articles now form a tightly connected CorgiNetwork advanced Linux networking cluster covering the complete path from ARP resolution → interface selection → policy rules → routing tables → gateways → reverse-path validation → packet-level troubleshooting.
AI Agents as Code: Managing AI Agent Configurations, Prompts and Tools with Git AI agents…
Data Center Power Distribution Architecture: UPS, PDU, Redundancy and Rack Power Explained Data center power…
DNSSEC Troubleshooting: Fix SERVFAIL & DNSKEY Errors DNSSEC Troubleshooting: How to Fix SERVFAIL, DS, DNSKEY…
Terraform State Management Explained: Remote State, Locking, Backends and Best Practices Terraform makes infrastructure reproducible…
RTO vs RPO Explained: Disaster Recovery Objectives, Examples and Planning A disaster recovery plan is…
Network Intrusion Detection Explained: NIDS, Sensors, Signatures and Traffic Analysis A firewall can decide whether…
View Comments