diff options
author | Xin Long <lucien.xin@gmail.com> | 2017-08-23 05:07:26 +0300 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2017-08-24 06:37:10 +0300 |
commit | 5f9ae3d9e7e4ad6db0491abc7c4ae5452dbeadd8 (patch) | |
tree | 12715edcb41529322205d32cd4a843f52978e850 /net/ipv4/fib_semantics.c | |
parent | d260e9e6ad6fd89488da0fa9e34a1a646ce670e1 (diff) | |
download | linux-5f9ae3d9e7e4ad6db0491abc7c4ae5452dbeadd8.tar.xz |
ipv4: do metrics match when looking up and deleting a route
Now when ipv4 route inserts a fib_info, it memcmp fib_metrics.
It means ipv4 route identifies one route also with metrics.
But when removing a route, it tries to find the route without
caring about the metrics. It will cause that the route with
right metrics can't be removed.
Thomas noticed this issue when doing the testing:
1. add:
# ip route append 192.168.7.0/24 dev v window 1000
# ip route append 192.168.7.0/24 dev v window 1001
# ip route append 192.168.7.0/24 dev v window 1002
# ip route append 192.168.7.0/24 dev v window 1003
2. delete:
# ip route delete 192.168.7.0/24 dev v window 1002
3. show:
192.168.7.0/24 proto boot scope link window 1001
192.168.7.0/24 proto boot scope link window 1002
192.168.7.0/24 proto boot scope link window 1003
The one with window 1002 wasn't deleted but the first one was.
This patch is to do metrics match when looking up and deleting
one route.
Reported-by: Thomas Haller <thaller@redhat.com>
Signed-off-by: Xin Long <lucien.xin@gmail.com>
Acked-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/fib_semantics.c')
-rw-r--r-- | net/ipv4/fib_semantics.c | 34 |
1 files changed, 34 insertions, 0 deletions
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index 394d800db50c..57a5d48acee8 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -696,6 +696,40 @@ int fib_nh_match(struct fib_config *cfg, struct fib_info *fi, return 0; } +bool fib_metrics_match(struct fib_config *cfg, struct fib_info *fi) +{ + struct nlattr *nla; + int remaining; + + if (!cfg->fc_mx) + return true; + + nla_for_each_attr(nla, cfg->fc_mx, cfg->fc_mx_len, remaining) { + int type = nla_type(nla); + u32 val; + + if (!type) + continue; + if (type > RTAX_MAX) + return false; + + if (type == RTAX_CC_ALGO) { + char tmp[TCP_CA_NAME_MAX]; + bool ecn_ca = false; + + nla_strlcpy(tmp, nla, sizeof(tmp)); + val = tcp_ca_get_key_by_name(tmp, &ecn_ca); + } else { + val = nla_get_u32(nla); + } + + if (fi->fib_metrics->metrics[type - 1] != val) + return false; + } + + return true; +} + /* * Picture |