Change in VLAN of bridge objects are not detected.
With libnl-3.5 running on Linux 4.14 kernel facing an issue while configuring VLAN for bridge object. For easy reproduction I modified the test program test-cache-mngr.c for receiving the notifications from a link. The code is as follows:
//allocate the cache manager
err = nl_cache_mngr_alloc(NULL, NETLINK_ROUTE, NL_AUTO_PROVIDE, &mngr);
//allocate the cache ops
nl_link_cops = nl_cache_ops_lookup_safe("route/link");
//allocate the cache for these cache ops
link_cache = nl_cache_alloc(nl_link_cops);
// add this cache to the cache manager
err = nl_cache_mngr_add_cache_v2(mngr, link_cache, &change_cb2, NULL);
//Poll in while loop for events
nl_cache_mngr_poll(mngr, 1000);
In the callback function (change_cb2) I am dumping the objects:
static void change_cb2(struct nl_cache *cache, struct nl_object *obj,
struct nl_object *n_obj, uint64_t outcome, int action,
void *data)
{
struct rtnl_link *link;
if (action == NL_ACT_NEW)
{
nl_object_dump(n_obj, &dp);
}
else if (action == NL_ACT_DEL)
{
nl_object_dump(n_obj, &dp);
}
else if (action == NL_ACT_CHANGE)
{
nl_object_dump(n_obj, &dp);
nl_object_dump(obj, &dp);
}
}
After creating a bridge I do following:
- Delete the PVLAN 1 // Post this step there are no VLAN's on bridge
- Add the PVLAN 10
- Add another VLAN 20
- Add another VLAN 30
- Delete VLAN 20
If I perform a deletion of VLAN on bridge interface I stopped getting any further notifications from the cache manager for any new VLAN addition or deletion.
Further debugging this issue revealed that when the deletion operation is performed on the bridge VLAN, libnl cache manager receives the netlink notifications however the logic to identify the change failed to classify it as a change due to which notifications are not sent to the cache manger callback. To fix this I was thinking of something following:
--- a/lib/route/link.c
+++ b/lib/route/link.c
@@ -1144,8 +1144,12 @@ static uint64_t link_compare(struct nl_object *_a, struct nl_object *_b,
* Compare LINK_ATTR_PROTINFO af_data
*/
if (a->l_family == b->l_family) {
- if (rtnl_link_af_data_compare(a, b, a->l_family) != 0)
+ uint64_t af_diff = 0;
+ af_diff = rtnl_link_af_data_compare(a, b, a->l_family);
+ if ((af_diff != 0) && (attrs == ~0)) {
+ diff |= af_diff;
goto protinfo_mismatch;
+ }
}
diff |= LINK_DIFF(LINKINFO, rtnl_link_info_data_compare(a, b, flags) != 0);
so that the identified diff can be propagated back to the caller of compare function.
I am more than happy to get any feedback on this.