Bug 197899 - iproute2: ip route list default shows non-default routes too
Summary: iproute2: ip route list default shows non-default routes too
Status: RESOLVED CODE_FIX
Alias: None
Product: Networking
Classification: Unclassified
Component: Other (show other bugs)
Hardware: All Linux
: P1 normal
Assignee: Stephen Hemminger
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2017-11-16 20:55 UTC by Alexander Zubkov
Modified: 2018-01-02 15:21 UTC (History)
0 users

See Also:
Kernel Version: any
Subsystem:
Regression: No
Bisected commit-id:


Attachments

Description Alexander Zubkov 2017-11-16 20:55:43 UTC
Hello.

I have found odd behaviour of ip route list command. It is reproducing at least on:
- Ubuntu 14.04.5 with 4.4.0-57-generic kernel and iproute 3.12.0-2ubuntu1
- Gentoo system with 4.12.14 kernel and iproute2 4.11.0
So I suppose it should be so on different versions of kernel and iproute2.

The problem is when ip specify "default" as a prefix in ip route list command - it shows all routes:

```
root@grape:~# ip route list default
default via 192.168.0.1 dev eth0 
default via 192.168.0.1 dev eth0  metric 2 
192.168.0.0/24 dev eth0  proto kernel  scope link  src 192.168.0.2 
192.168.2.0/24 via 192.168.0.1 dev eth0 
root@grape:~# ip route list exact default
default via 192.168.0.1 dev eth0 
default via 192.168.0.1 dev eth0  metric 2 
192.168.0.0/24 dev eth0  proto kernel  scope link  src 192.168.0.2 
192.168.2.0/24 via 192.168.0.1 dev eth0 
root@grape:~# ip route list match default
default via 192.168.0.1 dev eth0 
default via 192.168.0.1 dev eth0  metric 2 
192.168.0.0/24 dev eth0  proto kernel  scope link  src 192.168.0.2 
192.168.2.0/24 via 192.168.0.1 dev eth0 
```

It behaves correctly if I use 0/0 as a prefix or provide an ip family option:

```
root@grape:~# ip route list 0/0
default via 192.168.0.1 dev eth0 
default via 192.168.0.1 dev eth0  metric 2 
root@grape:~# ip -4 route list default
default via 192.168.0.1 dev eth0 
default via 192.168.0.1 dev eth0  metric 2 
```
Comment 1 Stephen Hemminger 2017-11-17 00:14:24 UTC
iproute2, like the rest of the Linux kernel networking does not really use bugzilla to handle bugs.

The commands are subtly different.

$ ip route list default
Means list all routes in any address family (ie same as any)
but

$ ip route list 0/0
Means list all routes for IPv4 default route.

It probably is worth a man page warning, but changing semantics
that have existed for many years is more likely to break some existing user.
Comment 2 Alexander Zubkov 2017-11-17 00:22:51 UTC
> iproute2, like the rest of the Linux kernel networking does not really use
> bugzilla to handle bugs.

Excuse me for that, where is the best place to bring up this question? May be netdev@vger.kernel.org?

> $ ip route list default
> Means list all routes in any address family (ie same as any)

Sorry, I still do not understand how it implies that it should print default and other routes too. This is not just default can be 0/0 or ::/0 (and this is written in man page).
Comment 3 Stephen Hemminger 2017-11-17 00:40:12 UTC
Yes use netdev@vger.kernel.org

$ ip route list default
Sets filter  as:
  
	if (strcmp(arg, "default") == 0 ||
	    strcmp(arg, "any") == 0 ||
	    strcmp(arg, "all") == 0) {
		if ((family == AF_DECnet) || (family == AF_MPLS))
			return -1;
		dst->family = family;
		dst->bytelen = 0;
		dst->bitlen = 0;
		return 0;
	}

Where 0/0 is from is ipv4 so dst->bitlen = 32

A 0 bit length prefix matches anything.
Comment 4 Alexander Zubkov 2017-11-17 00:55:37 UTC
And what changes when I specify family: "ip -4 route list default"?

And it looks like that bitlen is the mask lentght. So 0 is just normal here. Later that code sets:

                if (slash) {
                        if (get_netmask(&plen, slash+1, 0)
                            || plen > dst->bitlen) {
                                err = -1;
                                goto done;
                        }
                        dst->flags |= PREFIXLEN_SPECIFIED;
                        dst->bitlen = plen;
                }

So I suppose for 0/0 dst->bitlen should be 0 too.

Yes 0/0 should match any ip or cover any prefix. It will be ok if it show all routes for "ip route show root default" command. But "ip route list" by default works in "exact mode":

> And exact PREFIX (or just PREFIX) selects routes with this exact prefix.

As you can see, even if I specify "exact" selector explicitly or use "match" selector, which should show equal or greater prefixes. It still shows all routes.

root 0/0 - will show all prefixes
exact or match 0/0 - will show only default (0/0) prefixes

But

default = root 0/0
exact default = root 0/0
root default = root 0/0
match default = root 0/0
Comment 5 Alexander Zubkov 2017-11-17 01:17:43 UTC
I have added some debug output to print contents of filter.mdst for ip route list. Here is the results:

user@grape:~/tmp/iproute2$ ./ip/ip route show default >/dev/null
Dump prefix: flags=0, bytelen=0, bitlen=0, family=0

user@grape:~/tmp/iproute2$ ./ip/ip -4 route show default >/dev/null
Dump prefix: flags=0, bytelen=0, bitlen=0, family=2

user@grape:~/tmp/iproute2$ ./ip/ip route show 0/0 >/dev/null
Dump prefix: flags=1, bytelen=4, bitlen=0, family=2

So the difference is not in bitlen. Looks like family=0 works like match all not taking into the account the actual prefix parameters. But at the same time it outputs only inet4 routes. So it knows that it is working with inet4.
Comment 6 Alexander Zubkov 2018-01-02 15:21:24 UTC
I take the liberty to change status here because patches have been merged actually.

Note You need to log in before you can comment on or make changes to this bug.