thom311 / libnl

Netlink Library Suite
GNU Lesser General Public License v2.1
423 stars 311 forks source link

nl_cache_refill() cause removing IPv6 ECMP (multipath) routes #271

Open t0mmmy90 opened 3 years ago

t0mmmy90 commented 3 years ago

Hi,

I'm using libnl 3.5.0 and I've noticed that after refilling the cache by calling nl_cache_refill() my IPv6 ECMP routes become normal ones (with only 1 next hop).

In my code I'm checking routes updates using nl_cache_mngr_poll() but after a long time without any update I'm doing the cache refill using nl_cache_refill() to be sure I'm not missing any route. Recently I've noticed that after refill my default IPv6 route which had 2 next hops now has only 1 but in kernel it still has 2 (I'm checking with ip r s). I've checked it with the nl-route-list and it also shows 1 next hop.

It seems that this is caused by nl_cache_refill() calling internally nl_cache_pickup() instead of nl_cache_pickup_checkdup() which performs route_update added here https://lists.infradead.org/pipermail/libnl/2012-December/000836.html.

After locally modifying netlink_cache_refill() the issue is fixed (also nl-route-list shows correct number of next hops) but I'm sure there must be a reason why nl_cache_pickup() was used.

If there is any solution/workaround for this problem I would be grateful if you could share.

Regards

t0mmmy90 commented 3 years ago

Maybe I didn't understand it correctly but I think that in doc descriptions for bellowed functions should be swapped cause actually calling __nl_cache_pickup() with checkdup set to 1 is causing updates.

/**
 * Pickup a netlink dump response and put it into a cache.
 * @arg sk      Netlink socket.
 * @arg cache       Cache to put items into.
 *
 * Waits for netlink messages to arrive, parses them and puts them into
 * the specified cache.
 *
 * @return 0 on success or a negative error code.
 */
int nl_cache_pickup_checkdup(struct nl_sock *sk, struct nl_cache *cache)
{
    return __nl_cache_pickup(sk, cache, 1);
}

/**
 * Pickup a netlink dump response and put it into a cache.
 * @arg sk      Netlink socket.
 * @arg cache       Cache to put items into.
 *
 * Waits for netlink messages to arrive, parses them and puts them into
 * the specified cache. If an old object with same key attributes is
 * present in the cache, it is replaced with the new object.
 * If the old object type supports an update operation, an update is
 * attempted before a replace.
 *
 * @return 0 on success or a negative error code.
 */
int nl_cache_pickup(struct nl_sock *sk, struct nl_cache *cache)
{
    return __nl_cache_pickup(sk, cache, 0);
}