Hello again,
Things turned out to be not so hard. Please take a look at the attached patch.
I'm only not sure if RTA_PRIORITY is enough. Because the print_route
function prints "metric" also for some situations with RTA_METRICS,
which I haven't managed to understand.
On Fri, Nov 17, 2017 at 1:40 AM, Alexander Zubkov <[email protected]> wrote:
> Hello all,
>
> Currently routes in the Linux routing table have these "key" fields:
> prefix, tos, table, metric (as I know). I.e. we cannot have two
> different routes with the same set of this fields. And "ip route list"
> command can be provided with all but one of those fields. We cannot
> pass metric to it and this is inconvenient. I ask if this behaviour
> can be changed by someone. We can even use "secondary" fields, for
> example type, dev or via, but not metric unfortunately.
> Sorry, I can not provide patches. I have written code long time ago. I
> tried to trace it, but as I see it parses arguments and fills some
> structures. And then my tries to understand failed.
> I opened the bug: https://bugzilla.kernel.org/show_bug.cgi?id=197897,
> but I was pointed out that this mailing list is a better place for
> this question.
>
> --
> Alexander Zubkov
--- a/ip/iproute.c
+++ b/ip/iproute.c
@@ -126,6 +126,8 @@ static struct
int oif, oifmask;
int mark, markmask;
int realm, realmmask;
+ int have_metric;
+ __u32 metric;
inet_prefix rprefsrc;
inet_prefix rvia;
inet_prefix rdst;
@@ -288,6 +290,14 @@ static int filter_nlmsg(struct nlmsghdr *n, struct rtattr **tb, int host_len)
if ((mark ^ filter.mark) & filter.markmask)
return 0;
}
+ if (filter.have_metric) {
+ __u32 metric = 0;
+
+ if (tb[RTA_PRIORITY])
+ metric = rta_getattr_u32(tb[RTA_PRIORITY]);
+ if (filter.metric != metric)
+ return 0;
+ }
if (filter.flushb &&
r->rtm_family == AF_INET6 &&
r->rtm_dst_len == 0 &&
@@ -1518,6 +1528,16 @@ static int iproute_list_flush_or_save(int argc, char **argv, int action)
if (get_unsigned(&mark, *argv, 0))
invarg("invalid mark value", *argv);
filter.markmask = -1;
+ } else if (matches(*argv, "metric") == 0 ||
+ matches(*argv, "priority") == 0 ||
+ strcmp(*argv, "preference") == 0) {
+ __u32 metric;
+
+ NEXT_ARG();
+ if (get_u32(&metric, *argv, 0))
+ invarg("\"metric\" value is invalid\n", *argv);
+ filter.metric = metric;
+ filter.have_metric = 1;
} else if (strcmp(*argv, "via") == 0) {
int family;