[From nobody Sun May 29 05:38:44 2016
Received: from zmta01.collab.prod.int.phx2.redhat.com (LHLO
 zmta01.collab.prod.int.phx2.redhat.com) (10.5.81.8) by
 zmail21.collab.prod.int.phx2.redhat.com with LMTP; Mon, 2 Nov 2015 17:27:32
 -0500 (EST)
Received: from int-mx09.intmail.prod.int.phx2.redhat.com
 (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22]) by
 zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id CA5EC18550F
 for &lt;thaller@mail.corp.redhat.com&gt;; Mon,  2 Nov 2015 17:27:32 -0500 (EST)
Received: from mx1.redhat.com (ext-mx07.extmail.prod.ext.phx2.redhat.com
 [10.5.110.31]) by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4)
 with ESMTP id tA2MRWX4015797 (version=TLSv1/SSLv3
 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO) for
 &lt;thaller@redhat.com&gt;; Mon, 2 Nov 2015 17:27:32 -0500
Received: from mail-pa0-f46.google.com (mail-pa0-f46.google.com
 [209.85.220.46]) by mx1.redhat.com (Postfix) with ESMTPS id 9CBE5C0A160F
 for &lt;thaller@redhat.com&gt;; Mon,  2 Nov 2015 22:27:31 +0000 (UTC)
Received: by pacfv9 with SMTP id fv9so167662882pac.3 for
 &lt;thaller@redhat.com&gt;; Mon, 02 Nov 2015 14:27:30 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=cumulusnetworks.com; s=google; h=from:to:cc:subject:date:message-id;
 bh=r4/HfWD/97ZRpqr1RxqFf1/DA/7VYm4I3fGiA8RMbXk=;
 b=LBkTxoFRx5RwmfT+T6LyaPJMEIJ3qZYT3CrVEL3BTmCUnTUuggdzuTKoX3wytbrFXh
 us4reZ4YiZDe+iGFdDEUtn08bgAurWSTl9xhm48x5/hP0ECVDRWe86mIQ1nIXbiVEbz7
 fgrA0nMfMvjKj6q9ghsqKtJQ59iK2zDndiGsQ=
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net;
 s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id;
 bh=r4/HfWD/97ZRpqr1RxqFf1/DA/7VYm4I3fGiA8RMbXk=;
 b=F/uzN5Cg4V0Yp88aB9dIS9DmPqEworY6neqinbdahD+T8FyvrPCuP7ekVnIEtVlBs/
 td1EzHzwTM2CgBgPI5Q1n9Hgg30qxehSVteH/CQtoAzoD2AR/yE4WNcOOwIUL52tdkQ/
 m1OaWB9Q3lbMlpKjjkNN8VeRtWfUnfNHRoKqM6bxes61Og16hy5tvZIAYRLXKjyXF4CR
 ek9gfDD43gFozuKHBYXwrIp9nxIg03aIcZgxnIGTLEWDFHO4NbztbLf06AyhTydg1KxJ
 7wA5ouZSMcfC/CT+BV6IQM/SOTYkDyTAVOSqHGzHnIbiMBEkPXRwPdZ7IoYu+TzmxhwE XH6Q==
X-Gm-Message-State: ALoCoQlNtDrcSbuV4e2hMXftE4aabUnzwzUxMdv38psWXJIctYG9qHp6uuLkBtXT3ol4fTU5w3Fy
X-Received: by 10.68.65.104 with SMTP id w8mr29694479pbs.48.1446501940633;
 Mon, 02 Nov 2015 14:05:40 -0800 (PST)
Received: from hydra-01.cumulusnetworks.com ([216.129.126.126]) by
 smtp.googlemail.com with ESMTPSA id bz1sm25892966pab.20.2015.11.02.14.05.39
 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 02
 Nov 2015 14:05:40 -0800 (PST)
From: Roopa Prabhu &lt;roopa@cumulusnetworks.com&gt;
X-Google-Original-From: Roopa Prabhu
To: libnl@lists.infradead.org
Cc: thaller@redhat.com, roopa@cumulusnetworks.com
Subject: [PATCH 6/6] route: cache and object changes to support
 non-exclusive and append routes
Date: Mon,  2 Nov 2015 14:05:29 -0800
Message-Id: &lt;1446501929-32003-7-git-send-email-roopa@cumulusnetworks.com&gt;
X-RedHat-Spam-Score: 2.08 **
 (ANY_BOUNCE_MESSAGE, BAYES_50, BOUNCE_MESSAGE, DCC_REPUT_13_19, DKIM_SIGNED,
 DKIM_VALID, DKIM_VALID_AU, DSN_NO_MIMEVERSION, RCVD_IN_DNSWL_LOW,
 RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, URIBL_BLOCKED)
 209.85.220.46 mail-pa0-f46.google.com 209.85.220.46 mail-pa0-f46.google.com
 &lt;&gt;
X-Scanned-By: MIMEDefang 2.68 on 10.5.11.22
X-Scanned-By: MIMEDefang 2.78 on 10.5.110.31
Mime-Version: 1.0
Content-Transfer-Encoding: quoted-printable

From: Roopa Prabhu &lt;roopa@cumulusnetworks.com&gt;

Problem (ipv4 only):
Todays libnl route cache looks at prefix + tos + priority to lookup a
route object. To support route append operation, where routes with same
prefix + tos + priority but different nexthop information can co-exist,
we need to also look at nexthop info. Else we will wrongly store only
one route for all appended routes. This happens Because the libnl cache
inclusion process looks up a route by prefix + tos + priority and replaces
it with the new object with the same prefix + tos + priority.

Only adding nexthop attribute during lookup does not solve the whole
problem. Because NLM_F_REPLACE of objects needs special handling.

This patch implements route cache callback .co_cache_search_attrs_get and
route object callback .oo_hash_attrs_get to return appropriate attributes
for searching route objects depending on type of route and the netlink mess=
age
flags (NLM_F_APPEND or NLM_F_REPLACE). This is used during cache inclusion
process. Also adds ROUTE_ATTR_MULTIPATH to the list of route attribute keys=
 to
search.

Signed-off-by: Roopa Prabhu &lt;roopa@cumulusnetworks.com&gt;
---
 include/netlink/route/route.h |    8 ++++++
 lib/route/route.c             |   21 ++++++++++++++
 lib/route/route_obj.c         |   64 ++++++++++++++++++++++++++++++++-----=
----
 3 files changed, 79 insertions(+), 14 deletions(-)

diff --git a/include/netlink/route/route.h b/include/netlink/route/route.h
index 477250d..5ab17fe 100644
--- a/include/netlink/route/route.h
+++ b/include/netlink/route/route.h
@@ -46,6 +46,12 @@ struct rtnl_rtcacheinfo
 	uint32_t	rtci_tsage;
 };
=20
+#define rtnl_route_is_likely_ipv6_multipath(route) \
+		(route-&gt;rt_family =3D=3D AF_INET6 &amp;&amp; \
+		route-&gt;rt_table !=3D RT_TABLE_LOCAL &amp;&amp; \
+		rtnl_route_get_nnexthops(route) =3D=3D 1 &amp;&amp; \
+		rtnl_route_nh_get_gateway(rtnl_route_nexthop_n(route, 0)))
+
 extern struct nl_object_ops route_obj_ops;
=20
 extern struct rtnl_route *	rtnl_route_alloc(void);
@@ -97,6 +103,8 @@ extern int	rtnl_route_get_src_len(struct rtnl_route *);
=20
 extern void	rtnl_route_add_nexthop(struct rtnl_route *,
 				       struct rtnl_nexthop *);
+extern void	rtnl_route_add_nexthop_head(struct rtnl_route *,
+					    struct rtnl_nexthop *);
 extern void	rtnl_route_remove_nexthop(struct rtnl_route *,
 					  struct rtnl_nexthop *);
 extern struct nl_list_head *rtnl_route_get_nexthops(struct rtnl_route *);
diff --git a/lib/route/route.c b/lib/route/route.c
index 2985187..cb9d243 100644
--- a/lib/route/route.c
+++ b/lib/route/route.c
@@ -27,6 +27,26 @@
=20
 static struct nl_cache_ops rtnl_route_ops;
=20
+uint32_t route_cache_search_attr_get(struct nl_cache *cache,
+				     struct nl_object *needle)
+{
+	struct nl_object_ops *ops =3D needle-&gt;ce_ops;
+	struct rtnl_route *new_route =3D (struct rtnl_route *)needle;
+
+	/*
+	 * If route add req is a replace
+	 * or it is a ipv6 multipath route
+	 * then, we replace the existing object
+	 * in the cache. So, look for the first object
+	 * that matches the hash key attributes
+	 */
+	if ((needle-&gt;ce_msgflags &amp; NLM_F_REPLACE) ||
+		rtnl_route_is_likely_ipv6_multipath(new_route))
+		return ops-&gt;oo_hash_attrs_get(needle);
+	else
+		return ops-&gt;oo_id_attrs_get(needle);
+}
+
 static int route_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *=
who,
 			    struct nlmsghdr *nlh, struct nl_parser_param *pp)
 {
@@ -191,6 +211,7 @@ static struct nl_cache_ops rtnl_route_ops =3D {
 	.co_request_update	=3D route_request_update,
 	.co_msg_parser		=3D route_msg_parser,
 	.co_obj_ops		=3D &amp;route_obj_ops,
+	.co_cache_search_attrs_get =3D route_cache_search_attr_get,
 };
=20
 static void __init route_init(void)
diff --git a/lib/route/route_obj.c b/lib/route/route_obj.c
index 1d7ce57..7a4ea63 100644
--- a/lib/route/route_obj.c
+++ b/lib/route/route_obj.c
@@ -294,6 +294,26 @@ static void route_dump_stats(struct nl_object *obj, st=
ruct nl_dump_params *p)
 	}
 }
=20
+static uint32_t route_id_attrs_get(struct nl_object *obj)
+{
+	struct nl_object_ops *ops =3D obj-&gt;ce_ops;
+
+	if (!ops)
+		BUG();
+
+	return ops-&gt;oo_id_attrs | ROUTE_ATTR_MULTIPATH;
+}
+
+static uint32_t route_hash_attrs_get(struct nl_object *obj)
+{
+	struct nl_object_ops *ops =3D obj-&gt;ce_ops;
+
+	if (!ops)
+		BUG();
+
+	return ops-&gt;oo_id_attrs;
+}
+
 static void route_keygen(struct nl_object *obj, uint32_t *hashkey,
 			  uint32_t table_sz)
 {
@@ -463,15 +483,9 @@ static int route_update(struct nl_object *old_obj, str=
uct nl_object *new_obj)
 	 * route with multiple nexthops. The resulting object looks
 	 * similar to a ipv4 ECMP route
 	 */
-	if (new_route-&gt;rt_family !=3D AF_INET6 ||
-	    new_route-&gt;rt_table =3D=3D RT_TABLE_LOCAL)
-		return -NLE_OPNOTSUPP;
=20
-	/*
-	 * For routes that are already multipath,
-	 * or dont have a nexthop dont do anything
-	 */
-	if (rtnl_route_get_nnexthops(new_route) !=3D 1)
+
+	if (!rtnl_route_is_likely_ipv6_multipath(new_route))
 		return -NLE_OPNOTSUPP;
=20
 	/*
@@ -480,19 +494,31 @@ static int route_update(struct nl_object *old_obj, st=
ruct nl_object *new_obj)
 	 * filled or nothing at all
 	 */
 	new_nh =3D rtnl_route_nexthop_n(new_route, 0);
-	if (!new_nh || !rtnl_route_nh_get_gateway(new_nh))
-		return -NLE_OPNOTSUPP;
=20
 	switch(action) {
 	case RTM_NEWROUTE : {
-		struct rtnl_nexthop *cloned_nh;
+		struct rtnl_nexthop *cloned_nh, *first_nh;
=20
-		/*
-		 * Add the nexthop to old route
-		 */
 		cloned_nh =3D rtnl_route_nh_clone(new_nh);
 		if (!cloned_nh)
 			return -NLE_NOMEM;
+
+		if (new_obj-&gt;ce_msgflags &amp; NLM_F_REPLACE) {
+			/* If replace flag, we should replace the first
+			 * nexthop with the new one
+			 */
+			first_nh =3D rtnl_route_nexthop_n(old_route, 0);
+			if (first_nh)
+				rtnl_route_remove_nexthop(old_route,
+							first_nh);
+			rtnl_route_add_nexthop_head(old_route, cloned_nh);
+
+			return 0;
+		}
+
+		/*
+		 * Add the nexthop to old route
+		 */
 		rtnl_route_add_nexthop(old_route, cloned_nh);
=20
 		NL_DBG(2, &quot;Route obj %p updated. Added &quot;
@@ -838,6 +864,14 @@ void rtnl_route_add_nexthop(struct rtnl_route *route, =
struct rtnl_nexthop *nh)
 	route-&gt;ce_mask |=3D ROUTE_ATTR_MULTIPATH;
 }
=20
+void rtnl_route_add_nexthop_head(struct rtnl_route *route,
+		struct rtnl_nexthop *nh)
+{
+	nl_list_add_head(&amp;nh-&gt;rtnh_list, &amp;route-&gt;rt_nexthops);
+	route-&gt;rt_nr_nh++;
+	route-&gt;ce_mask |=3D ROUTE_ATTR_MULTIPATH;
+}
+
 void rtnl_route_remove_nexthop(struct rtnl_route *route, struct rtnl_nexth=
op *nh)
 {
 	if (route-&gt;ce_mask &amp; ROUTE_ATTR_MULTIPATH) {
@@ -1310,6 +1344,8 @@ struct nl_object_ops route_obj_ops =3D {
 	.oo_id_attrs		=3D (ROUTE_ATTR_FAMILY | ROUTE_ATTR_TOS |
 				   ROUTE_ATTR_TABLE | ROUTE_ATTR_DST |
 				   ROUTE_ATTR_PRIO),
+	.oo_id_attrs_get        =3D route_id_attrs_get,
+	.oo_hash_attrs_get      =3D route_hash_attrs_get
 };
 /** @endcond */
=20
--=20
1.7.10.4

]