In Linux, what metric has a route with no metric?
I would expect that the first one is used, but that’s not the case: the second one is used instead. If I change that to this:
default via 192.168.1.1 dev enp58s0f1 proto static metric 100 default via 192.168.16.1 dev wlp59s0 proto static metric 600
Then it works as expected. It seems that «no metric» is a worse (higher) metric than any number, instead of metric 0. What is this happening? Is it specific to Linux, or a networking standard? Thanks in advance.
3 Answers 3
Are you sure about your first observation? What does ip route show or route -n show then? Does the result change if you add proto static in first case?
I have found at least two resources that explicitely says that 0 is the default value in Linux:
- http://0pointer.de/lennart/projects/ifmetric/ : The default metric for a route in the Linux kernel is 0, meaning the highest priority.
- http://www.man7.org/linux/man-pages/man8/route.8.html : If this option is not specified the metric for inet6 (IPv6) address family defaults to ‘1’, for inet (IPv4) it defaults to ‘0’. (it then hints that the default may be different when using iproute2 but analysis of these sources do not show what it is)
A Linux kernel hacker would surely be needed to sort that out.
Also whatever default is chosen is clearly OS specific. This article (https://support.microsoft.com/en-us/help/299540/an-explanation-of-the-automatic-metric-feature-for-ipv4-routes) for example shows that Windows choose the default metric based on the bandwidth of the link.
I’m marking your answer as the right one because I’ve not seen again this behaviour in my computer. I’m blaming it in some weird thing that happens in desktop computers with Ubuntu, at least with the version that I had at the time of the question. I’ve not seen it happening in a few other boxes running Ubuntu LTS. So, a X-File (is that reference too old nowadays?). Thanks for your answer!
Since these routes are on different subnets, there’s more involved here than just the metric. If originating traffic is on the 192.168.1.1 subnet, for instance, and there is a matching non-default route in your routing table, then that route will match via longest prefix match before the metric is ever considered.
Assuming a non-default route is not matching, then having no metric should be interpreted by the kernel as having a metric of 0, and therefore the highest priority route. Although that’s a simplistic view because some routing daemons will later translate that default metric into another value like 1024. I expect this is what is happening to you and your unnamed distro.
If ip route shows no metric at all, you can confirm that it is indeed 0 by using the older route -n command from the net-tools package or cat /proc/net/route . However, this output doesn’t necessarily match what the routing daemon will use internally when it encounters a 0 metric value.
Furthermore how you create the route matters too. ip route uses the netlink API, while route uses ioctl. The code for how default metrics are created between the two approaches result in different metric values. For instance: creating an IPv6 default route via ip route will result in a metric value of 1024 on RHEL 7, while creating the same route via route will result in a metric of 1.
- if nothing is passed to the route command as route metric the value of 1 is used by the command itself.
- If nothing is passed to the ip command as route metric the attribute is not created at all and kernel understands to it as 0, which is later translated 1024 as default.
Network manager sets metrics by default by device type if they are not set otherwise. See man 5 nm-settings. Here is an excerpt, you can search for the word ‘metric’. Also note that they differ depending on ip v4 vs v6. not sure if this will help you or not.
┌───────────────────┬───────────────────┬───────────────┬────────────────────────┐ │Key Name │ Value Type │ Default Value │ Value Description │ ├───────────────────┼───────────────────┼───────────────┼────────────────────────┤ . ├───────────────────┼───────────────────┼───────────────┼────────────────────────┤ │route-data │ array of vardict │ │ Array of IPv4 routes. │ │ │ │ │ Each route dictionary │ │ │ │ │ contains at least │ │ │ │ │ 'dest' and 'prefix' │ │ │ │ │ entries, containing │ │ │ │ │ the destination IP │ │ │ │ │ address as a string, │ │ │ │ │ and the prefix length │ │ │ │ │ as a uint32. Most │ │ │ │ │ routes will also have │ │ │ │ │ a 'gateway' entry, │ │ │ │ │ containing the gateway │ │ │ │ │ IP address as a │ │ │ │ │ string. If the route │ │ │ │ │ has a 'metric' entry │ │ │ │ │ (containing a uint32), │ │ │ │ │ that will be used as │ │ │ │ │ the metric for the │ │ │ │ │ route (otherwise NM │ │ │ │ │ will pick a default │ │ │ │ │ value appropriate to │ │ │ │ │ the device). │ │ │ │ │ Additional attributes │ │ │ │ │ may also exist on some │ │ │ │ │ routes. │ ├───────────────────┼───────────────────┼───────────────┼────────────────────────┤ │route-metric │ int64 │ -1 │ The default metric for │ │ │ │ │ routes that don't │ │ │ │ │ explicitly specify a │ │ │ │ │ metric. The default │ │ │ │ │ value -1 means that │ │ │ │ │ the metric is chosen │ │ │ │ │ automatically based on │ │ │ │ │ the device type. The │ │ │ │ │ metric applies to │ │ │ │ │ dynamic routes, manual │ │ │ │ │ (static) routes that │ │ │ │ │ don't have an explicit │ │ │ │ │ metric setting, │ │ │ │ │ address prefix routes, │ │ │ │ │ and the default route. │ │ │ │ │ Note that for IPv6, │ │ │ │ │ the kernel accepts │ │ │ │ │ zero (0) but coerces │ │ │ │ │ it to 1024 (user │ │ │ │ │ default). Hence, │ │ │ │ │ setting this property │ │ │ │ │ to zero effectively │ │ │ │ │ mean setting it to │ │ │ │ │ 1024. For IPv4, zero │ │ │ │ │ is a regular value for │ │ │ │ │ the metric. │ ├───────────────────┼───────────────────┼───────────────┼────────────────────────┤ │route-table │ uint32 │ 0 │ Enable policy routing │ │ │ │ │ (source routing) and │ │ │ │ │ set the routing table │ │ │ │ │ used when adding │ │ │ │ │ routes. This affects │ │ │ │ │ all routes, including │ │ │ │ │ device-routes, IPv4LL, │ │ │ │ │ DHCP, SLAAC, │ │ │ │ │ default-routes and │ │ │ │ │ static routes. But │ │ │ │ │ note that static │ │ │ │ │ routes can │ │ │ │ │ individually overwrite │ │ │ │ │ the setting by │ │ │ │ │ explicitly specifying │ │ │ │ │ a non-zero routing │ │ │ │ │ table. If the table │ │ │ │ │ setting is left at │ │ │ │ │ zero, it is eligible │ │ │ │ │ to be overwritten via │ │ │ │ │ global configuration. │ │ │ │ │ If the property is │ │ │ │ │ zero even after │ │ │ │ │ applying the global │ │ │ │ │ configuration value, │ │ │ │ │ policy routing is │ │ │ │ │ disabled for the │ │ │ │ │ address family of this │ │ │ │ │ connection. Policy │ │ │ │ │ routing disabled means │ │ │ │ │ that NetworkManager │ │ │ │ │ will add all routes to │ │ │ │ │ the main table (except │ │ │ │ │ static routes that │ │ │ │ │ explicitly configure a │ │ │ │ │ different table). │ │ │ │ │ Additionally, │ │ │ │ │ NetworkManager will │ │ │ │ │ not delete any │ │ │ │ │ extraneous routes from │ │ │ │ │ tables except the main │ │ │ │ │ table. This is to │ │ │ │ │ preserve backward │ │ │ │ │ compatibility for │ │ │ │ │ users who manage │ │ │ │ │ routing tables outside │ │ │ │ │ of NetworkManager. │ ├───────────────────┼───────────────────┼───────────────┼────────────────────────┤ │routes │ array of array of │ [] │ Deprecated in favor of │ │ │ uint32 │ │ the 'route-data' │ │ │ │ │ property, but this can │ │ │ │ │ be used for │ │ │ │ │ backward-compatibility │ │ │ │ │ with older daemons. │ │ │ │ │ Note that if you send │ │ │ │ │ this property the │ │ │ │ │ daemon will ignore │ │ │ │ │ 'route-data'. Array │ │ │ │ │ of IPv4 route │ │ │ │ │ structures. Each IPv4 │ │ │ │ │ route structure is │ │ │ │ │ composed of 4 32-bit │ │ │ │ │ values; the first │ │ │ │ │ being the destination │ │ │ │ │ IPv4 network or │ │ │ │ │ address (network byte │ │ │ │ │ order), the second the │ │ │ │ │ destination network or │ │ │ │ │ address prefix (1 - │ │ │ │ │ 32), the third being │ │ │ │ │ the next-hop (network │ │ │ │ │ byte order) if any, │ │ │ │ │ and the fourth being │ │ │ │ │ the route metric. If │ │ │ │ │ the metric is 0, NM │ │ │ │ │ will choose an │ │ │ │ │ appropriate default │ │ │ │ │ metric for the device. │ │ │ │ │ (There is no way to │ │ │ │ │ explicitly specify an │ │ │ │ │ actual metric of 0 │ │ │ │ │ with this property.) │ └───────────────────┴───────────────────┴───────────────┴────────────────────────┘ ipv6 setting IPv6 Settings. ┌───────────────────┬───────────────────────────┬───────────────┬────────────────────────────────────────────────────┐ │Key Name │ Value Type │ Default Value │ Value Description │ ├───────────────────┼───────────────────────────┼───────────────┼────────────────────────────────────────────────────┤ . ├───────────────────┼───────────────────────────┼───────────────┼────────────────────────────────────────────────────┤ │route-data │ array of vardict │ │ Array of IPv6 routes. Each route dictionary │ │ │ │ │ contains at least 'dest' and 'prefix' entries, │ │ │ │ │ containing the destination IP address as a string, │ │ │ │ │ and the prefix length as a uint32. Most routes │ │ │ │ │ will also have a 'next-hop' entry, containing the │ │ │ │ │ next hop IP address as a string. If the route has │ │ │ │ │ a 'metric' entry (containing a uint32), that will │ │ │ │ │ be used as the metric for the route (otherwise NM │ │ │ │ │ will pick a default value appropriate to the │ │ │ │ │ device). Additional attributes may also exist on │ │ │ │ │ some routes. │ ├───────────────────┼───────────────────────────┼───────────────┼────────────────────────────────────────────────────┤ │route-metric │ int64 │ -1 │ The default metric for routes that don't │ │ │ │ │ explicitly specify a metric. The default value -1 │ │ │ │ │ means that the metric is chosen automatically │ │ │ │ │ based on the device type. The metric applies to │ │ │ │ │ dynamic routes, manual (static) routes that don't │ │ │ │ │ have an explicit metric setting, address prefix │ │ │ │ │ routes, and the default route. Note that for IPv6, │ │ │ │ │ the kernel accepts zero (0) but coerces it to 1024 │ │ │ │ │ (user default). Hence, setting this property to │ │ │ │ │ zero effectively mean setting it to 1024. For │ │ │ │ │ IPv4, zero is a regular value for the metric. │ ├───────────────────┼───────────────────────────┼───────────────┼────────────────────────────────────────────────────┤ │route-table │ uint32 │ 0 │ Enable policy routing (source routing) and set the │ │ │ │ │ routing table used when adding routes. This │ │ │ │ │ affects all routes, including device-routes, │ │ │ │ │ IPv4LL, DHCP, SLAAC, default-routes and static │ │ │ │ │ routes. But note that static routes can │ │ │ │ │ individually overwrite the setting by explicitly │ │ │ │ │ specifying a non-zero routing table. If the table │ │ │ │ │ setting is left at zero, it is eligible to be │ │ │ │ │ overwritten via global configuration. If the │ │ │ │ │ property is zero even after applying the global │ │ │ │ │ configuration value, policy routing is disabled │ │ │ │ │ for the address family of this connection. Policy │ │ │ │ │ routing disabled means that NetworkManager will │ │ │ │ │ add all routes to the main table (except static │ │ │ │ │ routes that explicitly configure a different │ │ │ │ │ table). Additionally, NetworkManager will not │ │ │ │ │ delete any extraneous routes from tables except │ │ │ │ │ the main table. This is to preserve backward │ │ │ │ │ compatibility for users who manage routing tables │ │ │ │ │ outside of NetworkManager. │ ├───────────────────┼───────────────────────────┼───────────────┼────────────────────────────────────────────────────┤ │routes │ array of legacy IPv6 │ [] │ Deprecated in favor of the 'route-data' property, │ │ │ route struct (a(ayuayu)) │ │ but this can be used for backward-compatibility │ │ │ │ │ with older daemons. Note that if you send this │ │ │ │ │ property the daemon will ignore 'route-data'. │ │ │ │ │ Array of IPv6 route structures. Each IPv6 route │ │ │ │ │ structure is composed of an IPv6 address, a prefix │ │ │ │ │ length (1 - 128), an IPv6 next hop address (which │ │ │ │ │ may be zeroed out if there is no next hop), and a │ │ │ │ │ metric. If the metric is 0, NM will choose an │ │ │ │ │ appropriate default metric for the device. │ ├───────────────────┼───────────────────────────┼───────────────┼────────────────────────────────────────────────────┤ │token │ string │ │ Configure the token for │ │ │ │ │ draft-chown-6man-tokenised-ipv6-identifiers-02 │ │ │ │ │ IPv6 tokenized interface identifiers. Useful with │ │ │ │ │ eui64 addr-gen-mode. │ └───────────────────┴───────────────────────────┴───────────────┴────────────────────────────────────────────────────┘