• Stefano Brivio's avatar
    ipv6: Dump route exceptions if requested · 1e47b483
    Stefano Brivio authored
    Since commit 2b760fcf ("ipv6: hook up exception table to store dst
    cache"), route exceptions reside in a separate hash table, and won't be
    found by walking the FIB, so they won't be dumped to userspace on a
    RTM_GETROUTE message.
    
    This causes 'ip -6 route list cache' and 'ip -6 route flush cache' to
    have no function anymore:
    
     # ip -6 route get fc00:3::1
     fc00:3::1 via fc00:1::2 dev veth_A-R1 src fc00:1::1 metric 1024 expires 539sec mtu 1400 pref medium
     # ip -6 route get fc00:4::1
     fc00:4::1 via fc00:2::2 dev veth_A-R2 src fc00:2::1 metric 1024 expires 536sec mtu 1500 pref medium
     # ip -6 route list cache
     # ip -6 route flush cache
     # ip -6 route get fc00:3::1
     fc00:3::1 via fc00:1::2 dev veth_A-R1 src fc00:1::1 metric 1024 expires 520sec mtu 1400 pref medium
     # ip -6 route get fc00:4::1
     fc00:4::1 via fc00:2::2 dev veth_A-R2 src fc00:2::1 metric 1024 expires 519sec mtu 1500 pref medium
    
    because iproute2 lists cached routes using RTM_GETROUTE, and flushes them
    by listing all the routes, and deleting them with RTM_DELROUTE one by one.
    
    If cached routes are requested using the RTM_F_CLONED flag together with
    strict checking, or if no strict checking is requested (and hence we can't
    consistently apply filters), look up exceptions in the hash table
    associated with the current fib6_info in rt6_dump_route(), and, if present
    and not expired, add them to the dump.
    
    We might be unable to dump all the entries for a given node in a single
    message, so keep track of how many entries were handled for the current
    node in fib6_walker, and skip that amount in case we start from the same
    partially dumped node.
    
    When a partial dump restarts, as the starting node might change when
    'sernum' changes, we have no guarantee that we need to skip the same
    amount of in-node entries. Therefore, we need two counters, and we need to
    zero the in-node counter if the node from which the dump is resumed
    differs.
    
    Note that, with the current version of iproute2, this only fixes the
    'ip -6 route list cache': on a flush command, iproute2 doesn't pass
    RTM_F_CLONED and, due to this inconsistency, 'ip -6 route flush cache' is
    still unable to fetch the routes to be flushed. This will be addressed in
    a patch for iproute2.
    
    To flush cached routes, a procfs entry could be introduced instead: that's
    how it works for IPv4. We already have a rt6_flush_exception() function
    ready to be wired to it. However, this would not solve the issue for
    listing.
    
    Versions of iproute2 and kernel tested:
    
                        iproute2
    kernel             4.14.0   4.15.0   4.19.0   5.0.0   5.1.0    5.1.0, patched
     3.18    list        +        +        +        +       +            +
             flush       +        +        +        +       +            +
     4.4     list        +        +        +        +       +            +
             flush       +        +        +        +       +            +
     4.9     list        +        +        +        +       +            +
             flush       +        +        +        +       +            +
     4.14    list        +        +        +        +       +            +
             flush       +        +        +        +       +            +
     4.15    list
             flush
     4.19    list
             flush
     5.0     list
             flush
     5.1     list
             flush
     with    list        +        +        +        +       +            +
     fix     flush       +        +        +                             +
    
    v7:
      - Explain usage of "skip" counters in commit message (suggested by
        David Ahern)
    
    v6:
      - Rebase onto net-next, use recently introduced nexthop walker
      - Make rt6_nh_dump_exceptions() a separate function (suggested by David
        Ahern)
    
    v5:
      - Use dump_routes and dump_exceptions from filter, ignore NLM_F_MATCH,
        update test results (flushing works with iproute2 < 5.0.0 now)
    
    v4:
      - Split NLM_F_MATCH and strict check handling in separate patches
      - Filter routes using RTM_F_CLONED: if it's not set, only return
        non-cached routes, and if it's set, only return cached routes:
        change requested by David Ahern and Martin Lau. This implies that
        iproute2 needs a separate patch to be able to flush IPv6 cached
        routes. This is not ideal because we can't fix the breakage caused
        by 2b760fcf entirely in kernel. However, two years have passed
        since then, and this makes it more tolerable
    
    v3:
      - More descriptive comment about expired exceptions in rt6_dump_route()
      - Swap return values of rt6_dump_route() (suggested by Martin Lau)
      - Don't zero skip_in_node in case we don't dump anything in a given pass
        (also suggested by Martin Lau)
      - Remove check on RTM_F_CLONED altogether: in the current UAPI semantic,
        it's just a flag to indicate the route was cloned, not to filter on
        routes
    
    v2: Add tracking of number of entries to be skipped in current node after
        a partial dump. As we restart from the same node, if not all the
        exceptions for a given node fit in a single message, the dump will
        not terminate, as suggested by Martin Lau. This is a concrete
        possibility, setting up a big number of exceptions for the same route
        actually causes the issue, suggested by David Ahern.
    Reported-by: default avatarJianlin Shi <jishi@redhat.com>
    Fixes: 2b760fcf ("ipv6: hook up exception table to store dst cache")
    Signed-off-by: default avatarStefano Brivio <sbrivio@redhat.com>
    Reviewed-by: default avatarDavid Ahern <dsahern@gmail.com>
    Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
    1e47b483
ip6_route.h 9.65 KB