diff mbox series

[iproute2-next,v4,1/3] lib/ll_map: cache alternative names

Message ID 20191019173749.19068-2-jiri@resnulli.us
State Changes Requested
Delegated to: David Ahern
Headers show
Series ip: add support for alternative names | expand

Commit Message

Jiri Pirko Oct. 19, 2019, 5:37 p.m. UTC
From: Jiri Pirko <jiri@mellanox.com>

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 <jiri@mellanox.com>
---
v3->v4:
- new patch
---
 lib/ll_map.c | 189 ++++++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 151 insertions(+), 38 deletions(-)

Comments

David Ahern Oct. 23, 2019, 3:11 p.m. UTC | #1
On 10/19/19 11:37 AM, Jiri Pirko wrote:
> +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);

you are walking a list and removing elements from it, so that should be
list_for_each_entry_safe, no?
Jiri Pirko Oct. 23, 2019, 4:08 p.m. UTC | #2
Wed, Oct 23, 2019 at 05:11:38PM CEST, dsahern@gmail.com wrote:
>On 10/19/19 11:37 AM, Jiri Pirko wrote:
>> +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);
>
>you are walking a list and removing elements from it, so that should be
>list_for_each_entry_safe, no?
>

You are correct. Will fix and send v5.
diff mbox series

Patch

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;
 }