diff mbox

[v5,1/1] ibacm: Add support for pathrecord query through netlink

Message ID 1434042265-5066-1-git-send-email-kaike.wan@intel.com (mailing list archive)
State Superseded
Headers show

Commit Message

Wan, Kaike June 11, 2015, 5:04 p.m. UTC
From: Kaike Wan <kaike.wan@intel.com>

This patch enables ibacm to process pathrecord queries through netlink.
Since ibacm can cache pathrecords, this implementation provides an easy
pathrecord cache for kernel components and therefore offers great
performance advantage on large fabric systems.

Signed-off-by: Kaike Wan <kaike.wan@intel.com>
Signed-off-by: John Fleck <john.fleck@intel.com>
Signed-off-by: Ira Weiny <ira.weiny@intel.com>
Reviewed-by: Sean Hefty <sean.hefty@intel.com>
---
Changes since v4:
- Add error handling for unknown or incorrectly formated attributes.
  The request will be NACKed.

Changes since v3:
- Change the parsing from struct ib_user_path_rec to basic attributes.

Changes since v2:
- Redesign the communication protocol between the kernel and ibacm, as
  described below:
  http://www.spinics.net/lists/linux-rdma/msg25621.html

Changes since v1:
- Check rmpp_flags for rmpp MAD instead of rmpp_version. 


 src/acm.c |  385 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 382 insertions(+), 3 deletions(-)

Comments

Jason Gunthorpe June 11, 2015, 5:59 p.m. UTC | #1
On Thu, Jun 11, 2015 at 01:04:25PM -0400, kaike.wan@intel.com wrote:
> +static int acm_nl_parse_path_attr(struct nlattr *attr,
> +				   struct acm_ep_addr_data *data)

> +	switch (attr->nla_type & NLA_TYPE_MASK) {
> +	default:
> +		acm_log(1, "WARN: unknown attr %x\n", attr->nla_type);
> +		ret = -1;
> +		break;

I would like to see a mandatory/optional scheme here.

For instance if we add SL it would be mandatory, but policy
information like requesting net_device would be optional.

Jason
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Wan, Kaike June 11, 2015, 6:31 p.m. UTC | #2
> From: Jason Gunthorpe [mailto:jgunthorpe@obsidianresearch.com]
> Sent: Thursday, June 11, 2015 2:00 PM
> To: Wan, Kaike
> Cc: linux-rdma@vger.kernel.org; Fleck, John; Weiny, Ira
> Subject: Re: [PATCH v5 1/1] ibacm: Add support for pathrecord query
> through netlink
> 
> On Thu, Jun 11, 2015 at 01:04:25PM -0400, kaike.wan@intel.com wrote:
> > +static int acm_nl_parse_path_attr(struct nlattr *attr,
> > +				   struct acm_ep_addr_data *data)
> 
> > +	switch (attr->nla_type & NLA_TYPE_MASK) {
> > +	default:
> > +		acm_log(1, "WARN: unknown attr %x\n", attr->nla_type);
> > +		ret = -1;
> > +		break;
> 
> I would like to see a mandatory/optional scheme here.
> 
> For instance if we add SL it would be mandatory, but policy information like
> requesting net_device would be optional.
> 

Are you saying the following:
1. all mandatory attributes must be present in the message. Otherwise, the request is invalid.
2. Optional attributes are optional. If they are absent, it is fine. If they are present, they can still be ignored, depending on the application.

Then what are the mandatory attributes: sgid, dgid, slid, dlid, pkey, reversise, qos, mtu, rate, or anything related to the pathrecord selection (can be used to set comp_mask during a query)?

What are the optional attributes?

Kaike
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Jason Gunthorpe June 11, 2015, 6:46 p.m. UTC | #3
On Thu, Jun 11, 2015 at 06:31:53PM +0000, Wan, Kaike wrote:
> 1. all mandatory attributes must be present in the
> message. Otherwise, the request is invalid.

All mandatory attributes that are present must be supported or the
user space side cannot answer the request.

> 2. Optional attributes are optional. If they are absent, it is
> fine. If they are present, they can still be ignored, depending on
> the application.

Yes

> Then what are the mandatory attributes: sgid, dgid, slid, dlid,
> pkey, reversise, qos, mtu, rate, or anything related to the
> pathrecord selection (can be used to set comp_mask during a query)?

Yes
 
> What are the optional attributes?

Future policy decision items, like the net device the query is being
made on behalf of, or the in-kernel ULP, etc.

Jason
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Wan, Kaike June 11, 2015, 6:52 p.m. UTC | #4
> From: Jason Gunthorpe [mailto:jgunthorpe@obsidianresearch.com]
> Sent: Thursday, June 11, 2015 2:47 PM
> To: Wan, Kaike
> Cc: linux-rdma@vger.kernel.org; Fleck, John; Weiny, Ira
> Subject: Re: [PATCH v5 1/1] ibacm: Add support for pathrecord query
> through netlink
> 
> On Thu, Jun 11, 2015 at 06:31:53PM +0000, Wan, Kaike wrote:
> > 1. all mandatory attributes must be present in the message. Otherwise,
> > the request is invalid.
> 
> All mandatory attributes that are present must be supported or the user
> space side cannot answer the request.

Then I will define all mandatory attribute types and check against them on the user space side.

> 
> > 2. Optional attributes are optional. If they are absent, it is fine.
> > If they are present, they can still be ignored, depending on the
> > application.
> 
> Yes
> 
> > Then what are the mandatory attributes: sgid, dgid, slid, dlid, pkey,
> > reversise, qos, mtu, rate, or anything related to the pathrecord
> > selection (can be used to set comp_mask during a query)?
> 
> Yes
> 
> > What are the optional attributes?
> 
> Future policy decision items, like the net device the query is being made on
> behalf of, or the in-kernel ULP, etc.
> 
> Jason
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Jason Gunthorpe June 11, 2015, 7:27 p.m. UTC | #5
On Thu, Jun 11, 2015 at 06:52:19PM +0000, Wan, Kaike wrote:
> > From: Jason Gunthorpe [mailto:jgunthorpe@obsidianresearch.com]
> > Sent: Thursday, June 11, 2015 2:47 PM
> > To: Wan, Kaike
> > Cc: linux-rdma@vger.kernel.org; Fleck, John; Weiny, Ira
> > Subject: Re: [PATCH v5 1/1] ibacm: Add support for pathrecord query
> > through netlink
> > 
> > On Thu, Jun 11, 2015 at 06:31:53PM +0000, Wan, Kaike wrote:
> > > 1. all mandatory attributes must be present in the message. Otherwise,
> > > the request is invalid.
> > 
> > All mandatory attributes that are present must be supported or the user
> > space side cannot answer the request.
> 
> Then I will define all mandatory attribute types and check against them on the user space side.

You need to handle the case where a new kernel gains a new mandatory
attribute type. A list in user space does not seem to handle that.

Jason
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Wan, Kaike June 11, 2015, 7:35 p.m. UTC | #6
> From: Jason Gunthorpe [mailto:jgunthorpe@obsidianresearch.com]
> Sent: Thursday, June 11, 2015 3:27 PM
> To: Wan, Kaike
> Cc: linux-rdma@vger.kernel.org; Fleck, John; Weiny, Ira
> Subject: Re: [PATCH v5 1/1] ibacm: Add support for pathrecord query
> through netlink
> 
> On Thu, Jun 11, 2015 at 06:52:19PM +0000, Wan, Kaike wrote:
> > > From: Jason Gunthorpe [mailto:jgunthorpe@obsidianresearch.com]
> > > Sent: Thursday, June 11, 2015 2:47 PM
> > > To: Wan, Kaike
> > > Cc: linux-rdma@vger.kernel.org; Fleck, John; Weiny, Ira
> > > Subject: Re: [PATCH v5 1/1] ibacm: Add support for pathrecord query
> > > through netlink
> > >
> > > On Thu, Jun 11, 2015 at 06:31:53PM +0000, Wan, Kaike wrote:
> > > > 1. all mandatory attributes must be present in the message.
> > > > Otherwise, the request is invalid.
> > >
> > > All mandatory attributes that are present must be supported or the
> > > user space side cannot answer the request.
> >
> > Then I will define all mandatory attribute types and check against them on
> the user space side.
> 
> You need to handle the case where a new kernel gains a new mandatory
> attribute type. A list in user space does not seem to handle that.

Can the mandatory list be defined within rdma_netlink.h and exported to user? or we use a new bit in attribute type (bit 13) to define the attribute as "Mandatory":

#define RDMA_NLA_F_MANDATORY   (1 << 13)
#define RDMA_NLA_TYPE_MASK  ~(NLA_F_NESTED | NLA_F_NET_BYTEORDER | RDMA_NLA_F_MANDATORY)

In this case, kernel will use (RDMA_NLA_F_MANDATORY | type) to inform user space that this attribute is mandatory.

> 
> Jason
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Jason Gunthorpe June 11, 2015, 7:54 p.m. UTC | #7
On Thu, Jun 11, 2015 at 07:35:37PM +0000, Wan, Kaike wrote:

> #define RDMA_NLA_F_MANDATORY   (1 << 13)
> #define RDMA_NLA_TYPE_MASK  ~(NLA_F_NESTED | NLA_F_NET_BYTEORDER | RDMA_NLA_F_MANDATORY)
> 
> In this case, kernel will use (RDMA_NLA_F_MANDATORY | type) to
> inform user space that this attribute is mandatory.

That general idea makes sense to me.

Then just test RDMA_NLA_F_MANDATORY in the case default: in acm. Fail
if set, ignore if unset.

Jason
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Ira Weiny June 11, 2015, 8:16 p.m. UTC | #8
> On Thu, Jun 11, 2015 at 01:04:25PM -0400, kaike.wan@intel.com wrote:
> > +static int acm_nl_parse_path_attr(struct nlattr *attr,
> > +				   struct acm_ep_addr_data *data)
> 
> > +	switch (attr->nla_type & NLA_TYPE_MASK) {
> > +	default:
> > +		acm_log(1, "WARN: unknown attr %x\n", attr->nla_type);
> > +		ret = -1;
> > +		break;
> 
> I would like to see a mandatory/optional scheme here.
> 
> For instance if we add SL it would be mandatory, but policy information like
> requesting net_device would be optional.

Why would SL be mandatory?

Ira
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Jason Gunthorpe June 11, 2015, 8:22 p.m. UTC | #9
On Thu, Jun 11, 2015 at 08:16:41PM +0000, Weiny, Ira wrote:
> > For instance if we add SL it would be mandatory, but policy information like
> > requesting net_device would be optional.
> 
> Why would SL be mandatory?

If the kernel asks for a specific SL then user space must respect that
and return a path with that exact SL.

If userspace does not know how to do that, then it must not answer the
query. It cannot ignore the SL requirement and return a random SL.

Hypothetically, assuming we add SL..

Jason
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Ira Weiny June 11, 2015, 8:55 p.m. UTC | #10
> 
> On Thu, Jun 11, 2015 at 08:16:41PM +0000, Weiny, Ira wrote:
> > > For instance if we add SL it would be mandatory, but policy
> > > information like requesting net_device would be optional.
> >
> > Why would SL be mandatory?
> 
> If the kernel asks for a specific SL then user space must respect that and return
> a path with that exact SL.
> 
> If userspace does not know how to do that, then it must not answer the query. It
> cannot ignore the SL requirement and return a random SL.

Oh, right, I misunderstood.  I thought that you were saying that SL would be mandatory as a netlink attribute.

> 
> Hypothetically, assuming we add SL..

Right...  ;-)

Ira
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/src/acm.c b/src/acm.c
index 7649725..bd64a93 100644
--- a/src/acm.c
+++ b/src/acm.c
@@ -46,6 +46,8 @@ 
 #include <infiniband/acm_prov.h>
 #include <infiniband/umad.h>
 #include <infiniband/verbs.h>
+#include <infiniband/umad_types.h>
+#include <infiniband/umad_sa.h>
 #include <dlist.h>
 #include <dlfcn.h> 
 #include <search.h>
@@ -55,6 +57,8 @@ 
 #include <netinet/in.h>
 #include <linux/netlink.h>
 #include <linux/rtnetlink.h>
+#include <rdma/rdma_netlink.h>
+#include <rdma/ib_user_sa.h>
 #include <poll.h>
 #include "acm_mad.h"
 #include "acm_util.h"
@@ -66,6 +70,7 @@ 
 #define MAX_EP_ADDR 4
 #define NL_MSG_BUF_SIZE 4096
 #define ACM_PROV_NAME_SIZE 64
+#define NL_CLIENT_INDEX 0
 
 struct acmc_subnet {
 	DLIST_ENTRY            entry;
@@ -151,6 +156,26 @@  struct acmc_sa_req {
 	struct acm_sa_mad	mad;
 };
 
+struct acm_nl_status {
+	struct nlattr			attr_hdr;
+	struct rdma_nla_ls_status	status;
+};
+
+struct acm_nl_path {
+	struct nlattr			attr_hdr;
+	struct ib_path_rec_data		rec;
+};
+
+struct acm_nl_msg {
+	struct nlmsghdr				nlmsg_header;
+	union {
+		uint8_t				data[ACM_MSG_DATA_LENGTH];
+		struct nlattr			attr[0];
+		struct acm_nl_status		status[0];
+		struct acm_nl_path		path[0];
+	};
+};
+
 static char def_prov_name[ACM_PROV_NAME_SIZE] = "ibacmp";
 static DLIST_ENTRY provider_list;
 static struct acmc_prov *def_provider = NULL;
@@ -172,6 +197,7 @@  static struct acmc_ep *acm_find_ep(struct acmc_port *port, uint16_t pkey);
 static int acm_ep_insert_addr(struct acmc_ep *ep, const char *name, uint8_t *addr,
 			      size_t addr_len, uint8_t addr_type);
 static void acm_event_handler(struct acmc_device *dev);
+static int acm_nl_send(SOCKET sock, struct acm_msg *msg);
 
 static struct sa_data {
 	int		timeout;
@@ -466,7 +492,11 @@  int acm_resolve_response(uint64_t id, struct acm_msg *msg)
 		goto release;
 	}
 
-	ret = send(client->sock, (char *) msg, msg->hdr.length, 0);
+	if (id == NL_CLIENT_INDEX)
+		ret = acm_nl_send(client->sock, msg);
+	else
+		ret = send(client->sock, (char *) msg, msg->hdr.length, 0);
+
 	if (ret != msg->hdr.length)
 		acm_log(0, "ERROR - failed to send response\n");
 	else
@@ -597,6 +627,8 @@  static void acm_svr_accept(void)
 	}
 
 	for (i = 0; i < FD_SETSIZE - 1; i++) {
+		if (i == NL_CLIENT_INDEX)
+			continue;
 		if (!atomic_get(&client_array[i].refcnt))
 			break;
 	}
@@ -1346,6 +1378,348 @@  static void acm_ipnl_handler(void)
 	}
 }
 
+static int acm_nl_send(SOCKET sock, struct acm_msg *msg)
+{
+	struct sockaddr_nl dst_addr;
+	struct acm_nl_msg acmnlmsg;
+	struct acm_nl_msg *orig;
+	int ret;
+	int datalen;
+
+	orig = (struct acm_nl_msg *) msg->hdr.tid;
+
+	memset(&dst_addr, 0, sizeof(dst_addr));
+	dst_addr.nl_family = AF_NETLINK;
+	dst_addr.nl_groups = (1 << (RDMA_NL_GROUP_LS - 1));
+
+	memset(&acmnlmsg, 0, sizeof(acmnlmsg));
+	acmnlmsg.nlmsg_header.nlmsg_len = NLMSG_HDRLEN;
+	acmnlmsg.nlmsg_header.nlmsg_pid = getpid();
+	acmnlmsg.nlmsg_header.nlmsg_type = orig->nlmsg_header.nlmsg_type;
+	acmnlmsg.nlmsg_header.nlmsg_flags = NLM_F_REQUEST;
+	acmnlmsg.nlmsg_header.nlmsg_seq = orig->nlmsg_header.nlmsg_seq;
+
+	if (msg->hdr.status != ACM_STATUS_SUCCESS) {
+		acm_log(2, "acm status no success = %d\n", msg->hdr.status);
+		acmnlmsg.nlmsg_header.nlmsg_flags |= RDMA_NL_LS_F_ERR;
+		acmnlmsg.nlmsg_header.nlmsg_len +=
+			NLA_ALIGN(sizeof(struct acm_nl_status));
+		acmnlmsg.status[0].attr_hdr.nla_type = LS_NLA_TYPE_STATUS;
+		acmnlmsg.status[0].attr_hdr.nla_len = NLA_HDRLEN +
+			sizeof(struct rdma_nla_ls_status);
+		if (msg->hdr.status == ACM_STATUS_EINVAL)
+			acmnlmsg.status[0].status.status = LS_NLA_STATUS_EINVAL;
+		else
+			acmnlmsg.status[0].status.status =
+				LS_NLA_STATUS_ENODATA;
+	} else {
+		acm_log(2, "acm status success\n");
+		acmnlmsg.nlmsg_header.nlmsg_flags |= RDMA_NL_LS_F_OK;
+		acmnlmsg.nlmsg_header.nlmsg_len +=
+			NLA_ALIGN(sizeof(struct acm_nl_path));
+		acmnlmsg.path[0].attr_hdr.nla_type = LS_NLA_TYPE_PATH_RECORD;
+		acmnlmsg.path[0].attr_hdr.nla_len = sizeof(struct acm_nl_path);
+		acmnlmsg.path[0].rec.flags =
+			IB_PATH_GMP | IB_PATH_PRIMARY | IB_PATH_BIDIRECTIONAL;
+		memcpy(acmnlmsg.path[0].rec.path_rec,
+		       &msg->resolve_data[0].info.path,
+		       sizeof(struct ibv_path_record));
+	}
+
+	datalen = NLMSG_ALIGN(acmnlmsg.nlmsg_header.nlmsg_len);
+	ret = sendto(sock, &acmnlmsg, datalen, 0,
+		     (const struct sockaddr *)&dst_addr,
+		     (socklen_t)sizeof(dst_addr));
+	if (ret != datalen) {
+		acm_log(0, "ERROR - sendto = %d errno = %d\n", ret, errno);
+		ret = -1;
+	} else {
+		ret = msg->hdr.length;
+	}
+
+	free(orig);
+
+	return ret;
+}
+
+#define NLA_LEN(nla)	((nla)->nla_len - NLA_HDRLEN)
+#define NLA_DATA(nla)	((char *)(nla) + NLA_HDRLEN)
+
+static int acm_nl_parse_path_attr(struct nlattr *attr,
+				   struct acm_ep_addr_data *data)
+{
+	struct ibv_path_record *path;
+	struct rdma_nla_ls_service_id  *sid;
+	struct rdma_nla_ls_gid *gid;
+	struct rdma_nla_ls_tclass *tcl;
+	struct rdma_nla_ls_reversible *rev;
+	struct rdma_nla_ls_numb_path *npath;
+	struct rdma_nla_ls_pkey *pkey;
+	struct rdma_nla_ls_qos_class *qos;
+	uint16_t val;
+	int ret = 0;
+
+#define IBV_PATH_RECORD_QOS_MASK 0xfff0
+
+	path = &data->info.path;
+	switch (attr->nla_type & NLA_TYPE_MASK) {
+	case LS_NLA_TYPE_SERVICE_ID:
+		sid = (struct rdma_nla_ls_service_id *) NLA_DATA(attr);
+		if (NLA_LEN(attr) == sizeof(sid->service_id)) {
+			acm_log(2, "service_id 0x%llx\n", sid->service_id);
+			path->service_id = sid->service_id;
+		} else {
+			ret = -1;
+		}
+		break;
+
+	case LS_NLA_TYPE_DGID:
+		gid = (struct rdma_nla_ls_gid *) NLA_DATA(attr);
+		if (NLA_LEN(attr) == sizeof(gid->gid)) {
+			acm_format_name(2, log_data, sizeof(log_data),
+					ACM_ADDRESS_GID, gid->gid,
+					sizeof(union ibv_gid));
+			acm_log(2, "path dgid %s\n", log_data);
+			memcpy(path->dgid.raw, gid->gid, sizeof(path->dgid));
+			data->flags |= ACM_EP_FLAG_DEST;
+		} else {
+			ret = -1;
+		}
+		break;
+
+	case LS_NLA_TYPE_SGID:
+		gid = (struct rdma_nla_ls_gid *) NLA_DATA(attr);
+		if (NLA_LEN(attr) == sizeof(gid->gid)) {
+			acm_format_name(2, log_data, sizeof(log_data),
+					ACM_ADDRESS_GID, gid->gid,
+					sizeof(union ibv_gid));
+			acm_log(2, "path sgid %s\n", log_data);
+			memcpy(path->sgid.raw, gid->gid, sizeof(path->sgid));
+			data->flags |= ACM_EP_FLAG_SOURCE;
+		} else {
+			ret = -1;
+		}
+		break;
+
+	case LS_NLA_TYPE_TCLASS:
+		tcl = (struct rdma_nla_ls_tclass *) NLA_DATA(attr);
+		if (NLA_LEN(attr) == sizeof(tcl->tclass)) {
+			acm_log(2, "tclass 0x%x\n", tcl->tclass);
+			path->tclass = tcl->tclass;
+		} else {
+			ret = -1;
+		}
+		break;
+
+	case LS_NLA_TYPE_REVERSIBLE:
+		rev = (struct rdma_nla_ls_reversible *) NLA_DATA(attr);
+		if (NLA_LEN(attr) == sizeof(rev->reversible)) {
+			acm_log(2, "reversible 0x%x\n", rev->reversible);
+			if (rev->reversible)
+				path->reversible_numpath |=
+					IBV_PATH_RECORD_REVERSIBLE;
+			else
+				path->reversible_numpath &=
+					~IBV_PATH_RECORD_REVERSIBLE;
+		} else {
+			ret = -1;
+		}
+		break;
+
+	case LS_NLA_TYPE_NUMB_PATH:
+		npath = (struct rdma_nla_ls_numb_path *) NLA_DATA(attr);
+		if (NLA_LEN(attr) == sizeof(npath->numb_path)) {
+			acm_log(2, "numb_path %d\n", npath->numb_path);
+			path->reversible_numpath &= IBV_PATH_RECORD_REVERSIBLE;
+			path->reversible_numpath |=
+				(npath->numb_path &
+				 (~IBV_PATH_RECORD_REVERSIBLE));
+		} else {
+			ret = -1;
+		}
+		break;
+
+	case LS_NLA_TYPE_PKEY:
+		pkey = (struct rdma_nla_ls_pkey *) NLA_DATA(attr);
+		if (NLA_LEN(attr) == sizeof(pkey->pkey)) {
+			acm_log(2, "pkey 0x%x\n", pkey->pkey);
+			path->pkey = pkey->pkey;
+		} else {
+			ret = -1;
+		}
+		break;
+
+	case LS_NLA_TYPE_QOS_CLASS:
+		qos = (struct rdma_nla_ls_qos_class *) NLA_DATA(attr);
+		if (NLA_LEN(attr) == sizeof(qos->qos_class)) {
+			acm_log(2, "qos_class 0x%x\n", qos->qos_class);
+			val = ntohs(path->qosclass_sl);
+			val &= ~IBV_PATH_RECORD_QOS_MASK;
+			val |= (ntohs(qos->qos_class) &
+				IBV_PATH_RECORD_QOS_MASK);
+			path->qosclass_sl = htons(val);
+		} else {
+			ret = -1;
+		}
+		break;
+
+	default:
+		acm_log(1, "WARN: unknown attr %x\n", attr->nla_type);
+		ret = -1;
+		break;
+	}
+
+	return ret;
+}
+
+static void acm_nl_process_invalid_request(struct acmc_client *client,
+					   struct acm_nl_msg *acmnlmsg)
+{
+	struct acm_msg msg;
+
+	memset(&msg, 0, sizeof(msg));
+	msg.hdr.opcode = ACM_OP_RESOLVE;
+	msg.hdr.version = ACM_VERSION;
+	msg.hdr.length = ACM_MSG_HDR_LENGTH;
+	msg.hdr.status = ACM_STATUS_EINVAL;
+	msg.hdr.tid = (uint64_t) acmnlmsg;
+
+	acm_nl_send(client->sock, &msg);
+}
+
+static void acm_nl_process_resolve(struct acmc_client *client,
+				   struct acm_nl_msg *acmnlmsg)
+{
+	struct acm_msg msg;
+	struct nlattr *attr;
+	int payload_len;
+	int rem;
+	int total_attr_len;
+	int status;
+
+	memset(&msg, 0, sizeof(msg));
+	msg.hdr.opcode = ACM_OP_RESOLVE;
+	msg.hdr.version = ACM_VERSION;
+	msg.hdr.length = ACM_MSG_HDR_LENGTH + ACM_MSG_EP_LENGTH;
+	msg.hdr.status = ACM_STATUS_SUCCESS;
+	msg.hdr.tid = (uint64_t) acmnlmsg;
+	msg.resolve_data[0].type = ACM_EP_INFO_PATH;
+
+	payload_len = acmnlmsg->nlmsg_header.nlmsg_len - NLMSG_HDRLEN;
+	attr = NLMSG_DATA(&acmnlmsg->nlmsg_header);
+	rem = payload_len;
+	while (1) {
+		if (rem < (int) sizeof(*attr) ||
+		    attr->nla_len < sizeof(*attr) ||
+		    attr->nla_len > rem)
+			break;
+
+		status = acm_nl_parse_path_attr(attr, &msg.resolve_data[0]);
+		if (status) {
+			acm_nl_process_invalid_request(client, acmnlmsg);
+			return;
+		}
+
+		/* Next attribute */
+		total_attr_len = NLA_ALIGN(attr->nla_len);
+		rem -= total_attr_len;
+		attr = (struct nlattr *) ((char *) attr + total_attr_len);
+	}
+
+	atomic_inc(&counter[ACM_CNTR_RESOLVE]);
+	acm_svr_resolve(client, &msg);
+}
+
+static int acm_nl_is_valid_resolve_request(struct acm_nl_msg *acmnlmsg)
+{
+	int payload_len;
+
+	payload_len = acmnlmsg->nlmsg_header.nlmsg_len - NLMSG_HDRLEN;
+	if (payload_len < sizeof(struct nlattr))
+		return 0;
+
+	return 1;
+}
+
+static void acm_nl_receive(struct acmc_client *client)
+{
+	struct acm_nl_msg *acmnlmsg;
+	int datalen = sizeof(*acmnlmsg);
+	int ret;
+	uint16_t client_inx, op;
+
+	acmnlmsg = calloc(1, sizeof(*acmnlmsg));
+	if (!acmnlmsg) {
+		acm_log(0, "Out of memory for recving nl msg.\n");
+		return;
+	}
+	ret = recv(client->sock, acmnlmsg, datalen, 0);
+	if (!NLMSG_OK(&acmnlmsg->nlmsg_header, ret)) {
+		acm_log(0, "Netlink receive error: %d.\n", ret);
+		goto rcv_cleanup;
+	}
+
+	acm_log(2, "nlmsg: len %d type 0x%x flags 0x%x seq %d pid %d\n",
+		acmnlmsg->nlmsg_header.nlmsg_len,
+		acmnlmsg->nlmsg_header.nlmsg_type,
+		acmnlmsg->nlmsg_header.nlmsg_flags,
+		acmnlmsg->nlmsg_header.nlmsg_seq,
+		acmnlmsg->nlmsg_header.nlmsg_pid);
+
+	/* Currently we handle only request from the SA client */
+	client_inx = RDMA_NL_GET_CLIENT(acmnlmsg->nlmsg_header.nlmsg_type);
+	op = RDMA_NL_GET_OP(acmnlmsg->nlmsg_header.nlmsg_type);
+	if (client_inx != RDMA_NL_SA)
+		goto rcv_cleanup;
+
+	switch (op) {
+	case RDMA_NL_LS_OP_RESOLVE:
+		if (acm_nl_is_valid_resolve_request(acmnlmsg))
+			acm_nl_process_resolve(client, acmnlmsg);
+		else
+			acm_nl_process_invalid_request(client, acmnlmsg);
+		break;
+	default:
+		/* Not supported*/
+		acm_log(1, "WARN - invalid opcode %x\n", op);
+		acm_nl_process_invalid_request(client, acmnlmsg);
+		break;
+	}
+
+	return;
+rcv_cleanup:
+	free(acmnlmsg);
+}
+
+static int acm_init_nl(void)
+{
+	struct sockaddr_nl src_addr;
+	int ret;
+	SOCKET nl_rcv_socket;
+
+	nl_rcv_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_RDMA);
+	if (nl_rcv_socket == INVALID_SOCKET) {
+		acm_log(0, "ERROR - unable to allocate netlink recv socket\n");
+		return socket_errno();
+	}
+
+	memset(&src_addr, 0, sizeof(src_addr));
+	src_addr.nl_family = AF_NETLINK;
+	src_addr.nl_pid = getpid();
+	src_addr.nl_groups = (1 << (RDMA_NL_GROUP_LS - 1));
+
+	ret = bind(nl_rcv_socket, (struct sockaddr *)&src_addr,
+		   sizeof(src_addr));
+	if (ret == SOCKET_ERROR) {
+		acm_log(0, "ERROR - unable to bind netlink socket\n");
+		return socket_errno();
+	}
+
+	/* init nl client structure */
+	client_array[NL_CLIENT_INDEX].sock = nl_rcv_socket;
+	return 0;
+}
+
 static void acm_server(void)
 {
 	fd_set readfds;
@@ -1360,12 +1734,14 @@  static void acm_server(void)
 		acm_log(0, "ERROR - server listen failed\n");
 		return;
 	}
+	ret = acm_init_nl();
+	if (ret)
+		acm_log(1, "Warn - Netlink init failed\n");
 
 	while (1) {
 		n = (int) listen_socket;
 		FD_ZERO(&readfds);
 		FD_SET(listen_socket, &readfds);
-
 		n = max(n, (int) ip_mon_socket);
 		FD_SET(ip_mon_socket, &readfds);
 
@@ -1399,7 +1775,10 @@  static void acm_server(void)
 			if (client_array[i].sock != INVALID_SOCKET &&
 				FD_ISSET(client_array[i].sock, &readfds)) {
 				acm_log(2, "receiving from client %d\n", i);
-				acm_svr_receive(&client_array[i]);
+				if (i == NL_CLIENT_INDEX)
+					acm_nl_receive(&client_array[i]);
+				else
+					acm_svr_receive(&client_array[i]);
 			}
 		}