From: Jiri Pirko <[email protected]> Alternative names are related to the "parent name". That means, whenever ll_remember_index() is called to add/delete/update and it founds the "parent name" im object by ifindex, processes related alternative name im objects too. Put them in a list which holds the relationship with the parent.
Signed-off-by: Jiri Pirko <[email protected]> --- v3->v4: - new patch --- lib/ll_map.c | 189 ++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 151 insertions(+), 38 deletions(-) diff --git a/lib/ll_map.c b/lib/ll_map.c index e0ed54bf77c9..1b382b5cec94 100644 --- a/lib/ll_map.c +++ b/lib/ll_map.c @@ -22,6 +22,7 @@ #include "libnetlink.h" #include "ll_map.h" #include "list.h" +#include "utils.h" struct ll_cache { struct hlist_node idx_hash; @@ -29,6 +30,7 @@ struct ll_cache { unsigned flags; unsigned index; unsigned short type; + struct list_head altnames_list; char name[]; }; @@ -77,10 +79,149 @@ static struct ll_cache *ll_get_by_name(const char *name) return NULL; } -int ll_remember_index(struct nlmsghdr *n, void *arg) +static struct ll_cache *ll_entry_create(struct ifinfomsg *ifi, + const char *ifname, + struct ll_cache *parent_im) { + struct ll_cache *im; unsigned int h; - const char *ifname; + + im = malloc(sizeof(*im) + strlen(ifname) + 1); + if (!im) + return NULL; + im->index = ifi->ifi_index; + strcpy(im->name, ifname); + im->type = ifi->ifi_type; + im->flags = ifi->ifi_flags; + + if (parent_im) { + list_add_tail(&im->altnames_list, &parent_im->altnames_list); + } else { + /* This is parent, insert to index hash. */ + h = ifi->ifi_index & (IDXMAP_SIZE - 1); + hlist_add_head(&im->idx_hash, &idx_head[h]); + INIT_LIST_HEAD(&im->altnames_list); + } + + h = namehash(ifname) & (IDXMAP_SIZE - 1); + hlist_add_head(&im->name_hash, &name_head[h]); + return im; +} + +static void ll_entry_destroy(struct ll_cache *im, bool im_is_parent) +{ + hlist_del(&im->name_hash); + if (im_is_parent) + hlist_del(&im->idx_hash); + else + list_del(&im->altnames_list); + free(im); +} + +static void ll_entry_update(struct ll_cache *im, struct ifinfomsg *ifi, + const char *ifname) +{ + unsigned int h; + + im->flags = ifi->ifi_flags; + if (!strcmp(im->name, ifname)) + return; + hlist_del(&im->name_hash); + h = namehash(ifname) & (IDXMAP_SIZE - 1); + hlist_add_head(&im->name_hash, &name_head[h]); +} + +static void ll_altname_entries_create(struct ll_cache *parent_im, + struct ifinfomsg *ifi, struct rtattr **tb) +{ + struct rtattr *i, *proplist = tb[IFLA_PROP_LIST]; + int rem; + + if (!proplist) + return; + rem = RTA_PAYLOAD(proplist); + for (i = RTA_DATA(proplist); RTA_OK(i, rem); + i = RTA_NEXT(i, rem)) { + if (i->rta_type != IFLA_ALT_IFNAME) + continue; + ll_entry_create(ifi, rta_getattr_str(i), parent_im); + } +} + +static void ll_altname_entries_destroy(struct ll_cache *parent_im) +{ + struct ll_cache *im; + + list_for_each_entry(im, &parent_im->altnames_list, altnames_list) + ll_entry_destroy(im, false); +} + +static void ll_altname_entries_update(struct ll_cache *parent_im, + struct ifinfomsg *ifi, struct rtattr **tb) +{ + struct rtattr *i, *proplist = tb[IFLA_PROP_LIST]; + struct ll_cache *im; + int rem; + + if (!proplist) { + ll_altname_entries_destroy(parent_im); + return; + } + + /* Simply compare the altname list with the cached one + * and if it does not fit 1:1, recreate the cached list + * from scratch. + */ + im = list_first_entry(&parent_im->altnames_list, typeof(*im), + altnames_list); + rem = RTA_PAYLOAD(proplist); + for (i = RTA_DATA(proplist); RTA_OK(i, rem); + i = RTA_NEXT(i, rem)) { + if (i->rta_type != IFLA_ALT_IFNAME) + continue; + if (!im || strcmp(rta_getattr_str(i), im->name)) + goto recreate_altname_entries; + im = list_next_entry(im, altnames_list); + } + if (list_next_entry(im, altnames_list)) + goto recreate_altname_entries; + return; + +recreate_altname_entries: + ll_altname_entries_destroy(parent_im); + ll_altname_entries_create(parent_im, ifi, tb); +} + +static void ll_entries_create(struct ifinfomsg *ifi, struct rtattr **tb) +{ + struct ll_cache *parent_im; + + if (!tb[IFLA_IFNAME]) + return; + parent_im = ll_entry_create(ifi, rta_getattr_str(tb[IFLA_IFNAME]), + NULL); + if (!parent_im) + return; + ll_altname_entries_create(parent_im, ifi, tb); +} + +static void ll_entries_destroy(struct ll_cache *parent_im) +{ + ll_altname_entries_destroy(parent_im); + ll_entry_destroy(parent_im, true); +} + +static void ll_entries_update(struct ll_cache *parent_im, + struct ifinfomsg *ifi, struct rtattr **tb) +{ + if (tb[IFLA_IFNAME]) + ll_entry_update(parent_im, ifi, + rta_getattr_str(tb[IFLA_IFNAME])); + ll_altname_entries_update(parent_im, ifi, tb); +} + +int ll_remember_index(struct nlmsghdr *n, void *arg) +{ struct ifinfomsg *ifi = NLMSG_DATA(n); struct ll_cache *im; struct rtattr *tb[IFLA_MAX+1]; @@ -93,45 +234,17 @@ int ll_remember_index(struct nlmsghdr *n, void *arg) im = ll_get_by_index(ifi->ifi_index); if (n->nlmsg_type == RTM_DELLINK) { - if (im) { - hlist_del(&im->name_hash); - hlist_del(&im->idx_hash); - free(im); - } - return 0; - } - - parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), IFLA_PAYLOAD(n)); - ifname = rta_getattr_str(tb[IFLA_IFNAME]); - if (ifname == NULL) - return 0; - - if (im) { - /* change to existing entry */ - if (strcmp(im->name, ifname) != 0) { - hlist_del(&im->name_hash); - h = namehash(ifname) & (IDXMAP_SIZE - 1); - hlist_add_head(&im->name_hash, &name_head[h]); - } - - im->flags = ifi->ifi_flags; + if (im) + ll_entries_destroy(im); return 0; } - im = malloc(sizeof(*im) + strlen(ifname) + 1); - if (im == NULL) - return 0; - im->index = ifi->ifi_index; - strcpy(im->name, ifname); - im->type = ifi->ifi_type; - im->flags = ifi->ifi_flags; - - h = ifi->ifi_index & (IDXMAP_SIZE - 1); - hlist_add_head(&im->idx_hash, &idx_head[h]); - - h = namehash(ifname) & (IDXMAP_SIZE - 1); - hlist_add_head(&im->name_hash, &name_head[h]); - + parse_rtattr_flags(tb, IFLA_MAX, IFLA_RTA(ifi), + IFLA_PAYLOAD(n), NLA_F_NESTED); + if (im) + ll_entries_update(im, ifi, tb); + else + ll_entries_create(ifi, tb); return 0; } -- 2.21.0
