From: Matan Barak <mat...@mellanox.com>

Add uverbs support for RoCE (IBoE) IP based addressing extensions
towards user space libraries.

Under ip based gid addressing, for RC QPs, QP attributes should contain the
Ethernet L2 destination. Until now, indicatings GID was sufficient. When
using ip encoded in gids, the QP attributes should contain extended destination,
indicating vlan and dmac as well. This is done via a new struct 
ib_uverbs_qp_dest_ex.
This new structure is contained in a new struct ib_uverbs_modify_qp_ex that is
used by MODIFY_QP_EX command. In order to make those changes seamlessly, those
extended structures were added in the bottom of the current structures.

Also, when the gid encodes ip address, the AH attributes should contain also
vlan and dmac. Therefore, ib_uverbs_create_ah was extended to contain those 
fields.
When creating an AH, the user indicates the exact L2 ethernet destination
parameters. This is done by a new CREATE_AH_EX command that uses a new struct
ib_uverbs_create_ah_ex.

struct ib_user_path_rec was extended too, to contain source and destination
MAC and VLAN ID, this structure is of use by the rdma_ucm driver.

Signed-off-by: Matan Barak <mat...@mellanox.com>
Signed-off-by: Or Gerlitz <ogerl...@mellanox.com>
---
 drivers/infiniband/core/uverbs.h          |    2 +
 drivers/infiniband/core/uverbs_cmd.c      |  330 ++++++++++++++++++++++-------
 drivers/infiniband/core/uverbs_main.c     |    4 +-
 drivers/infiniband/core/uverbs_marshall.c |   94 ++++++++-
 include/rdma/ib_marshall.h                |   12 +
 include/uapi/rdma/ib_user_sa.h            |   34 +++-
 include/uapi/rdma/ib_user_verbs.h         |  120 +++++++++++-
 7 files changed, 503 insertions(+), 93 deletions(-)

diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h
index 0fcd7aa..1ec4850 100644
--- a/drivers/infiniband/core/uverbs.h
+++ b/drivers/infiniband/core/uverbs.h
@@ -200,11 +200,13 @@ IB_UVERBS_DECLARE_CMD(create_qp);
 IB_UVERBS_DECLARE_CMD(open_qp);
 IB_UVERBS_DECLARE_CMD(query_qp);
 IB_UVERBS_DECLARE_CMD(modify_qp);
+IB_UVERBS_DECLARE_CMD(modify_qp_ex);
 IB_UVERBS_DECLARE_CMD(destroy_qp);
 IB_UVERBS_DECLARE_CMD(post_send);
 IB_UVERBS_DECLARE_CMD(post_recv);
 IB_UVERBS_DECLARE_CMD(post_srq_recv);
 IB_UVERBS_DECLARE_CMD(create_ah);
+IB_UVERBS_DECLARE_CMD(create_ah_ex);
 IB_UVERBS_DECLARE_CMD(destroy_ah);
 IB_UVERBS_DECLARE_CMD(attach_mcast);
 IB_UVERBS_DECLARE_CMD(detach_mcast);
diff --git a/drivers/infiniband/core/uverbs_cmd.c 
b/drivers/infiniband/core/uverbs_cmd.c
index a7d00f6..eb3e7e6 100644
--- a/drivers/infiniband/core/uverbs_cmd.c
+++ b/drivers/infiniband/core/uverbs_cmd.c
@@ -1891,6 +1891,58 @@ static int modify_qp_mask(enum ib_qp_type qp_type, int 
mask)
        }
 }
 
+static void ib_uverbs_modify_qp_assign(struct ib_uverbs_modify_qp *cmd,
+                                      struct ib_qp_attr *attr) {
+       attr->qp_state            = cmd->qp_state;
+       attr->cur_qp_state        = cmd->cur_qp_state;
+       attr->path_mtu            = cmd->path_mtu;
+       attr->path_mig_state      = cmd->path_mig_state;
+       attr->qkey                = cmd->qkey;
+       attr->rq_psn              = cmd->rq_psn;
+       attr->sq_psn              = cmd->sq_psn;
+       attr->dest_qp_num         = cmd->dest_qp_num;
+       attr->qp_access_flags     = cmd->qp_access_flags;
+       attr->pkey_index          = cmd->pkey_index;
+       attr->alt_pkey_index      = cmd->alt_pkey_index;
+       attr->en_sqd_async_notify = cmd->en_sqd_async_notify;
+       attr->max_rd_atomic       = cmd->max_rd_atomic;
+       attr->max_dest_rd_atomic  = cmd->max_dest_rd_atomic;
+       attr->min_rnr_timer       = cmd->min_rnr_timer;
+       attr->port_num            = cmd->port_num;
+       attr->timeout             = cmd->timeout;
+       attr->retry_cnt           = cmd->retry_cnt;
+       attr->rnr_retry           = cmd->rnr_retry;
+       attr->alt_port_num        = cmd->alt_port_num;
+       attr->alt_timeout         = cmd->alt_timeout;
+
+       memcpy(attr->ah_attr.grh.dgid.raw, cmd->dest.dgid, 16);
+       attr->ah_attr.grh.flow_label        = cmd->dest.flow_label;
+       attr->ah_attr.grh.sgid_index        = cmd->dest.sgid_index;
+       attr->ah_attr.grh.hop_limit         = cmd->dest.hop_limit;
+       attr->ah_attr.grh.traffic_class     = cmd->dest.traffic_class;
+       attr->ah_attr.dlid                  = cmd->dest.dlid;
+       attr->ah_attr.sl                    = cmd->dest.sl;
+       attr->ah_attr.src_path_bits         = cmd->dest.src_path_bits;
+       attr->ah_attr.static_rate           = cmd->dest.static_rate;
+       attr->ah_attr.ah_flags              = cmd->dest.is_global ?
+                                             IB_AH_GRH : 0;
+       attr->ah_attr.port_num              = cmd->dest.port_num;
+
+       memcpy(attr->alt_ah_attr.grh.dgid.raw, cmd->alt_dest.dgid, 16);
+       attr->alt_ah_attr.grh.flow_label    = cmd->alt_dest.flow_label;
+       attr->alt_ah_attr.grh.sgid_index    = cmd->alt_dest.sgid_index;
+       attr->alt_ah_attr.grh.hop_limit     = cmd->alt_dest.hop_limit;
+       attr->alt_ah_attr.grh.traffic_class = cmd->alt_dest.traffic_class;
+       attr->alt_ah_attr.dlid              = cmd->alt_dest.dlid;
+       attr->alt_ah_attr.sl                = cmd->alt_dest.sl;
+       attr->alt_ah_attr.src_path_bits     = cmd->alt_dest.src_path_bits;
+       attr->alt_ah_attr.static_rate       = cmd->alt_dest.static_rate;
+       attr->alt_ah_attr.ah_flags          = cmd->alt_dest.is_global
+                                             ? IB_AH_GRH : 0;
+       attr->alt_ah_attr.port_num          = cmd->alt_dest.port_num;
+}
+
+
 ssize_t ib_uverbs_modify_qp(struct ib_uverbs_file *file,
                            const char __user *buf, int in_len,
                            int out_len)
@@ -1917,51 +1969,11 @@ ssize_t ib_uverbs_modify_qp(struct ib_uverbs_file *file,
                goto out;
        }
 
-       attr->qp_state            = cmd.qp_state;
-       attr->cur_qp_state        = cmd.cur_qp_state;
-       attr->path_mtu            = cmd.path_mtu;
-       attr->path_mig_state      = cmd.path_mig_state;
-       attr->qkey                = cmd.qkey;
-       attr->rq_psn              = cmd.rq_psn;
-       attr->sq_psn              = cmd.sq_psn;
-       attr->dest_qp_num         = cmd.dest_qp_num;
-       attr->qp_access_flags     = cmd.qp_access_flags;
-       attr->pkey_index          = cmd.pkey_index;
-       attr->alt_pkey_index      = cmd.alt_pkey_index;
-       attr->en_sqd_async_notify = cmd.en_sqd_async_notify;
-       attr->max_rd_atomic       = cmd.max_rd_atomic;
-       attr->max_dest_rd_atomic  = cmd.max_dest_rd_atomic;
-       attr->min_rnr_timer       = cmd.min_rnr_timer;
-       attr->port_num            = cmd.port_num;
-       attr->timeout             = cmd.timeout;
-       attr->retry_cnt           = cmd.retry_cnt;
-       attr->rnr_retry           = cmd.rnr_retry;
-       attr->alt_port_num        = cmd.alt_port_num;
-       attr->alt_timeout         = cmd.alt_timeout;
-
-       memcpy(attr->ah_attr.grh.dgid.raw, cmd.dest.dgid, 16);
-       attr->ah_attr.grh.flow_label        = cmd.dest.flow_label;
-       attr->ah_attr.grh.sgid_index        = cmd.dest.sgid_index;
-       attr->ah_attr.grh.hop_limit         = cmd.dest.hop_limit;
-       attr->ah_attr.grh.traffic_class     = cmd.dest.traffic_class;
-       attr->ah_attr.dlid                  = cmd.dest.dlid;
-       attr->ah_attr.sl                    = cmd.dest.sl;
-       attr->ah_attr.src_path_bits         = cmd.dest.src_path_bits;
-       attr->ah_attr.static_rate           = cmd.dest.static_rate;
-       attr->ah_attr.ah_flags              = cmd.dest.is_global ? IB_AH_GRH : 
0;
-       attr->ah_attr.port_num              = cmd.dest.port_num;
-
-       memcpy(attr->alt_ah_attr.grh.dgid.raw, cmd.alt_dest.dgid, 16);
-       attr->alt_ah_attr.grh.flow_label    = cmd.alt_dest.flow_label;
-       attr->alt_ah_attr.grh.sgid_index    = cmd.alt_dest.sgid_index;
-       attr->alt_ah_attr.grh.hop_limit     = cmd.alt_dest.hop_limit;
-       attr->alt_ah_attr.grh.traffic_class = cmd.alt_dest.traffic_class;
-       attr->alt_ah_attr.dlid              = cmd.alt_dest.dlid;
-       attr->alt_ah_attr.sl                = cmd.alt_dest.sl;
-       attr->alt_ah_attr.src_path_bits     = cmd.alt_dest.src_path_bits;
-       attr->alt_ah_attr.static_rate       = cmd.alt_dest.static_rate;
-       attr->alt_ah_attr.ah_flags          = cmd.alt_dest.is_global ? 
IB_AH_GRH : 0;
-       attr->alt_ah_attr.port_num          = cmd.alt_dest.port_num;
+       ib_uverbs_modify_qp_assign(&cmd, attr);
+       memset(attr->ah_attr.dmac, 0, sizeof(attr->ah_attr.dmac));
+       attr->ah_attr.vlan = 0xFFFF;
+       memset(attr->alt_ah_attr.dmac, 0, sizeof(attr->alt_ah_attr.dmac));
+       attr->alt_ah_attr.vlan = 0xFFFF;
 
        if (qp->real_qp == qp) {
                ret = qp->device->modify_qp(qp, attr,
@@ -1983,6 +1995,80 @@ out:
        return ret;
 }
 
+ssize_t ib_uverbs_modify_qp_ex(struct ib_uverbs_file *file,
+                              const char __user *buf, int in_len,
+                              int out_len)
+{
+       struct ib_uverbs_modify_qp_ex cmd;
+       struct ib_udata               udata;
+       struct ib_qp                 *qp;
+       struct ib_qp_attr            *attr;
+       int                           ret;
+
+       if (copy_from_user(&cmd, buf, sizeof(cmd)))
+               return -EFAULT;
+
+       INIT_UDATA(&udata, buf + sizeof(cmd), NULL, in_len - sizeof(cmd),
+                  out_len);
+
+       attr = kmalloc(sizeof(*attr), GFP_KERNEL);
+       if (!attr)
+               return -ENOMEM;
+
+       qp = idr_read_qp(cmd.qp_handle, file->ucontext);
+       if (!qp) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       ib_uverbs_modify_qp_assign((struct ib_uverbs_modify_qp *)((void *)&cmd +
+                                   sizeof(cmd.comp_mask)), attr);
+
+       if (cmd.comp_mask & IB_UVERBS_MODIFY_QP_EX_DEST_EX_FLAGS) {
+               if (cmd.dest_ex.comp_mask & IBV_QP_DEST_EX_DMAC)
+                       memcpy(attr->ah_attr.dmac, cmd.dest_ex.dmac,
+                              sizeof(attr->ah_attr.dmac));
+               else
+                       memset(attr->ah_attr.dmac, 0,
+                              sizeof(attr->ah_attr.dmac));
+               if (cmd.dest_ex.comp_mask & IBV_QP_DEST_EX_VID)
+                       attr->ah_attr.vlan = cmd.dest_ex.vid;
+               else
+                       attr->ah_attr.vlan = 0xFFFF;
+       }
+       if (cmd.comp_mask & IB_UVERBS_MODIFY_QP_EX_ALT_DEST_EX_FLAGS) {
+               if (cmd.alt_dest_ex.comp_mask & IBV_QP_DEST_EX_DMAC)
+                       memcpy(attr->alt_ah_attr.dmac, cmd.alt_dest_ex.dmac,
+                              sizeof(attr->alt_ah_attr.dmac));
+               else
+                       memset(attr->alt_ah_attr.dmac, 0,
+                              sizeof(attr->alt_ah_attr.dmac));
+               if (cmd.alt_dest_ex.comp_mask & IBV_QP_DEST_EX_VID)
+                       attr->alt_ah_attr.vlan = cmd.alt_dest_ex.vid;
+               else
+                       attr->alt_ah_attr.vlan = 0xFFFF;
+       }
+
+       if (qp->real_qp == qp) {
+               ret = qp->device->modify_qp(qp, attr,
+                       modify_qp_mask(qp->qp_type, cmd.attr_mask), &udata);
+       } else {
+               ret = ib_modify_qp(qp, attr,
+                                  modify_qp_mask(qp->qp_type, cmd.attr_mask));
+       }
+
+       put_qp_read(qp);
+
+       if (ret)
+               goto out;
+
+       ret = in_len;
+
+out:
+       kfree(attr);
+
+       return ret;
+}
 ssize_t ib_uverbs_destroy_qp(struct ib_uverbs_file *file,
                             const char __user *buf, int in_len,
                             int out_len)
@@ -2377,48 +2463,51 @@ out:
        return ret ? ret : in_len;
 }
 
-ssize_t ib_uverbs_create_ah(struct ib_uverbs_file *file,
-                           const char __user *buf, int in_len,
-                           int out_len)
+struct ib_uobject *ib_uverbs_create_ah_assign(
+               struct ib_uverbs_create_ah_ex *cmd,
+               struct ib_uverbs_ah_attr_ex *src_attr,
+               struct ib_uverbs_file *file)
 {
-       struct ib_uverbs_create_ah       cmd;
-       struct ib_uverbs_create_ah_resp  resp;
-       struct ib_uobject               *uobj;
        struct ib_pd                    *pd;
        struct ib_ah                    *ah;
        struct ib_ah_attr               attr;
-       int ret;
-
-       if (out_len < sizeof resp)
-               return -ENOSPC;
-
-       if (copy_from_user(&cmd, buf, sizeof cmd))
-               return -EFAULT;
+       struct ib_uobject               *uobj;
+       long                            ret;
 
-       uobj = kmalloc(sizeof *uobj, GFP_KERNEL);
+       uobj = kmalloc(sizeof(*uobj), GFP_KERNEL);
        if (!uobj)
-               return -ENOMEM;
+               return (void *)-ENOMEM;
 
-       init_uobj(uobj, cmd.user_handle, file->ucontext, &ah_lock_class);
+       init_uobj(uobj, cmd->user_handle, file->ucontext, &ah_lock_class);
        down_write(&uobj->mutex);
 
-       pd = idr_read_pd(cmd.pd_handle, file->ucontext);
+       pd = idr_read_pd(cmd->pd_handle, file->ucontext);
        if (!pd) {
                ret = -EINVAL;
                goto err;
        }
 
-       attr.dlid              = cmd.attr.dlid;
-       attr.sl                = cmd.attr.sl;
-       attr.src_path_bits     = cmd.attr.src_path_bits;
-       attr.static_rate       = cmd.attr.static_rate;
-       attr.ah_flags          = cmd.attr.is_global ? IB_AH_GRH : 0;
-       attr.port_num          = cmd.attr.port_num;
-       attr.grh.flow_label    = cmd.attr.grh.flow_label;
-       attr.grh.sgid_index    = cmd.attr.grh.sgid_index;
-       attr.grh.hop_limit     = cmd.attr.grh.hop_limit;
-       attr.grh.traffic_class = cmd.attr.grh.traffic_class;
-       memcpy(attr.grh.dgid.raw, cmd.attr.grh.dgid, 16);
+       attr.dlid              = src_attr->dlid;
+       attr.sl                = src_attr->sl;
+       attr.src_path_bits     = src_attr->src_path_bits;
+       attr.static_rate       = src_attr->static_rate;
+       attr.ah_flags          = src_attr->is_global ? IB_AH_GRH : 0;
+       attr.port_num          = src_attr->port_num;
+       attr.grh.flow_label    = src_attr->grh.flow_label;
+       attr.grh.sgid_index    = src_attr->grh.sgid_index;
+       attr.grh.hop_limit     = src_attr->grh.hop_limit;
+       attr.grh.traffic_class = src_attr->grh.traffic_class;
+       memcpy(attr.grh.dgid.raw, src_attr->grh.dgid, 16);
+
+       if (src_attr->comp_mask & IB_UVERBS_AH_ATTR_DMAC)
+               memcpy(attr.dmac, src_attr->dmac, sizeof(attr.dmac));
+       else
+               memset(attr.dmac, 0, sizeof(attr.dmac));
+
+       if (src_attr->comp_mask & IB_UVERBS_AH_ATTR_VID)
+               attr.vlan = src_attr->vlan;
+       else
+               attr.vlan = 0xFFFF;
 
        ah = ib_create_ah(pd, &attr);
        if (IS_ERR(ah)) {
@@ -2427,22 +2516,62 @@ ssize_t ib_uverbs_create_ah(struct ib_uverbs_file *file,
        }
 
        ah->uobject  = uobj;
+
        uobj->object = ah;
 
        ret = idr_add_uobj(&ib_uverbs_ah_idr, uobj);
        if (ret)
                goto err_destroy;
 
+       put_pd_read(pd);
+
+       return uobj;
+
+err_destroy:
+       ib_destroy_ah(ah);
+err_put:
+       put_pd_read(pd);
+err:
+       put_uobj_write(uobj);
+       return (void *)ret;
+}
+
+ssize_t ib_uverbs_create_ah(struct ib_uverbs_file *file,
+                           const char __user *buf, int in_len,
+                           int out_len)
+{
+       struct ib_uverbs_create_ah_ex    cmd_ex;
+       struct ib_uverbs_create_ah      *cmd = (struct ib_uverbs_create_ah *)
+                                              ((void *)&cmd_ex +
+                                               sizeof(cmd_ex.comp_mask));
+       struct ib_uverbs_ah_attr_ex      attr_ex;
+       struct ib_uverbs_create_ah_resp  resp;
+       struct ib_uobject               *uobj;
+       int ret;
+
+       if (out_len < sizeof(resp))
+               return -ENOSPC;
+
+       cmd_ex.comp_mask = 0;
+       if (copy_from_user(cmd, buf, sizeof(*cmd)))
+               return -EFAULT;
+
+       attr_ex.comp_mask = 0;
+       memcpy(((void *)&attr_ex) + sizeof(attr_ex.comp_mask),
+              &cmd->attr, sizeof(cmd->attr));
+
+       uobj = ib_uverbs_create_ah_assign(&cmd_ex,  &attr_ex, file);
+       if (IS_ERR(uobj))
+               return (ssize_t)uobj;
+
        resp.ah_handle = uobj->id;
 
-       if (copy_to_user((void __user *) (unsigned long) cmd.response,
+       if (copy_to_user((void __user *)(unsigned long) cmd->response,
                         &resp, sizeof resp)) {
                ret = -EFAULT;
                goto err_copy;
        }
 
-       put_pd_read(pd);
-
        mutex_lock(&file->mutex);
        list_add_tail(&uobj->list, &file->ucontext->ah_list);
        mutex_unlock(&file->mutex);
@@ -2455,15 +2584,54 @@ ssize_t ib_uverbs_create_ah(struct ib_uverbs_file *file,
 
 err_copy:
        idr_remove_uobj(&ib_uverbs_ah_idr, uobj);
+       ib_destroy_ah(uobj->object);
+       put_uobj_write(uobj);
 
-err_destroy:
-       ib_destroy_ah(ah);
+       return ret;
+}
 
-err_put:
-       put_pd_read(pd);
+ssize_t ib_uverbs_create_ah_ex(struct ib_uverbs_file *file,
+                              const char __user *buf, int in_len,
+                              int out_len)
+{
+       struct ib_uverbs_create_ah_ex    cmd_ex;
+       struct ib_uverbs_create_ah_resp  resp;
+       struct ib_uobject               *uobj;
+       int ret;
 
-err:
+       if (out_len < sizeof(resp))
+               return -ENOSPC;
+
+       if (copy_from_user(&cmd_ex, buf, sizeof(cmd_ex)))
+               return -EFAULT;
+
+       uobj = ib_uverbs_create_ah_assign(&cmd_ex,  &cmd_ex.attr, file);
+       if (IS_ERR(uobj))
+               return (ssize_t)uobj;
+
+       resp.ah_handle = uobj->id;
+
+       if (copy_to_user((void __user *)(unsigned long)cmd_ex.response,
+                        &resp, sizeof(resp))) {
+               ret = -EFAULT;
+               goto err_copy;
+       }
+
+       mutex_lock(&file->mutex);
+       list_add_tail(&uobj->list, &file->ucontext->ah_list);
+       mutex_unlock(&file->mutex);
+
+       uobj->live = 1;
+
+       up_write(&uobj->mutex);
+
+       return in_len;
+
+err_copy:
+       idr_remove_uobj(&ib_uverbs_ah_idr, uobj);
+       ib_destroy_ah(uobj->object);
        put_uobj_write(uobj);
+
        return ret;
 }
 
diff --git a/drivers/infiniband/core/uverbs_main.c 
b/drivers/infiniband/core/uverbs_main.c
index e4e7b24..93264c8 100644
--- a/drivers/infiniband/core/uverbs_main.c
+++ b/drivers/infiniband/core/uverbs_main.c
@@ -113,7 +113,9 @@ static ssize_t (*uverbs_cmd_table[])(struct ib_uverbs_file 
*file,
        [IB_USER_VERBS_CMD_OPEN_XRCD]           = ib_uverbs_open_xrcd,
        [IB_USER_VERBS_CMD_CLOSE_XRCD]          = ib_uverbs_close_xrcd,
        [IB_USER_VERBS_CMD_CREATE_XSRQ]         = ib_uverbs_create_xsrq,
-       [IB_USER_VERBS_CMD_OPEN_QP]             = ib_uverbs_open_qp
+       [IB_USER_VERBS_CMD_OPEN_QP]             = ib_uverbs_open_qp,
+       [IB_USER_VERBS_CMD_MODIFY_QP_EX]        = ib_uverbs_modify_qp_ex,
+       [IB_USER_VERBS_CMD_CREATE_AH_EX]        = ib_uverbs_create_ah_ex,
 };
 
 static void ib_uverbs_add_one(struct ib_device *device);
diff --git a/drivers/infiniband/core/uverbs_marshall.c 
b/drivers/infiniband/core/uverbs_marshall.c
index e7bee46..0470407 100644
--- a/drivers/infiniband/core/uverbs_marshall.c
+++ b/drivers/infiniband/core/uverbs_marshall.c
@@ -33,6 +33,9 @@
 #include <linux/export.h>
 #include <rdma/ib_marshall.h>
 
+#define UVERB_EX_TO_UVERB(uverb_ex) ((void *)(uverb_ex) + \
+                                    sizeof(uverb_ex->comp_mask))
+
 void ib_copy_ah_attr_to_user(struct ib_uverbs_ah_attr *dst,
                             struct ib_ah_attr *src)
 {
@@ -52,9 +55,20 @@ void ib_copy_ah_attr_to_user(struct ib_uverbs_ah_attr *dst,
 }
 EXPORT_SYMBOL(ib_copy_ah_attr_to_user);
 
-void ib_copy_qp_attr_to_user(struct ib_uverbs_qp_attr *dst,
-                            struct ib_qp_attr *src)
+void ib_copy_ah_attr_to_user_ex(struct ib_uverbs_ah_attr_ex *dst,
+                               struct ib_ah_attr *src)
 {
+       ib_copy_ah_attr_to_user((struct ib_uverbs_ah_attr *)
+                               UVERB_EX_TO_UVERB(dst), src);
+       dst->comp_mask = IB_UVERBS_AH_ATTR_DMAC;
+       memcpy(dst->dmac, src->dmac, sizeof(dst->dmac));
+       dst->comp_mask = IB_UVERBS_AH_ATTR_VID;
+       dst->vlan                  = src->vlan;
+}
+EXPORT_SYMBOL(ib_copy_ah_attr_to_user_ex);
+
+static void ib_copy_qp_attr_to_user_data(struct ib_uverbs_qp_attr *dst,
+                                        struct ib_qp_attr *src) {
        dst->qp_state           = src->qp_state;
        dst->cur_qp_state       = src->cur_qp_state;
        dst->path_mtu           = src->path_mtu;
@@ -71,9 +85,6 @@ void ib_copy_qp_attr_to_user(struct ib_uverbs_qp_attr *dst,
        dst->max_recv_sge       = src->cap.max_recv_sge;
        dst->max_inline_data    = src->cap.max_inline_data;
 
-       ib_copy_ah_attr_to_user(&dst->ah_attr, &src->ah_attr);
-       ib_copy_ah_attr_to_user(&dst->alt_ah_attr, &src->alt_ah_attr);
-
        dst->pkey_index         = src->pkey_index;
        dst->alt_pkey_index     = src->alt_pkey_index;
        dst->en_sqd_async_notify = src->en_sqd_async_notify;
@@ -89,8 +100,26 @@ void ib_copy_qp_attr_to_user(struct ib_uverbs_qp_attr *dst,
        dst->alt_timeout        = src->alt_timeout;
        memset(dst->reserved, 0, sizeof(dst->reserved));
 }
+
+void ib_copy_qp_attr_to_user(struct ib_uverbs_qp_attr *dst,
+                            struct ib_qp_attr *src)
+{
+       ib_copy_qp_attr_to_user_data(dst, src);
+       ib_copy_ah_attr_to_user(&dst->ah_attr, &src->ah_attr);
+       ib_copy_ah_attr_to_user(&dst->alt_ah_attr, &src->alt_ah_attr);
+}
 EXPORT_SYMBOL(ib_copy_qp_attr_to_user);
 
+void ib_copy_qp_attr_to_user_ex(struct ib_uverbs_qp_attr_ex *dst,
+                               struct ib_qp_attr *src)
+{
+       ib_copy_qp_attr_to_user_data((struct ib_uverbs_qp_attr *)
+                                    UVERB_EX_TO_UVERB(dst), src);
+       ib_copy_ah_attr_to_user_ex(&dst->ah_attr, &src->ah_attr);
+       ib_copy_ah_attr_to_user_ex(&dst->alt_ah_attr, &src->alt_ah_attr);
+}
+EXPORT_SYMBOL(ib_copy_qp_attr_to_user_ex);
+
 void ib_copy_path_rec_to_user(struct ib_user_path_rec *dst,
                              struct ib_sa_path_rec *src)
 {
@@ -117,11 +146,27 @@ void ib_copy_path_rec_to_user(struct ib_user_path_rec 
*dst,
 }
 EXPORT_SYMBOL(ib_copy_path_rec_to_user);
 
-void ib_copy_path_rec_from_user(struct ib_sa_path_rec *dst,
-                               struct ib_user_path_rec *src)
+void ib_copy_path_rec_to_user_ex(struct ib_user_path_rec_ex *dst,
+                                struct ib_sa_path_rec *src)
+{
+       ib_copy_path_rec_to_user((struct ib_user_path_rec *)
+                                 UVERB_EX_TO_UVERB(dst), src);
+
+       dst->comp_mask = IB_USER_PATH_REC_ATTR_DMAC |
+                        IB_USER_PATH_REC_ATTR_SMAC |
+                        IB_USER_PATH_REC_ATTR_VID;
+
+       memcpy(dst->dmac, src->dmac, sizeof(dst->dmac));
+       memcpy(dst->smac, src->smac, sizeof(dst->smac));
+       dst->vlan = src->vlan;
+}
+EXPORT_SYMBOL(ib_copy_path_rec_to_user_ex);
+
+void ib_copy_path_rec_from_user_assign(struct ib_sa_path_rec *dst,
+                                      struct ib_user_path_rec *src)
 {
-       memcpy(dst->dgid.raw, src->dgid, sizeof dst->dgid);
-       memcpy(dst->sgid.raw, src->sgid, sizeof dst->sgid);
+       memcpy(dst->dgid.raw, src->dgid, sizeof(dst->dgid));
+       memcpy(dst->sgid.raw, src->sgid, sizeof(dst->sgid));
 
        dst->dlid               = src->dlid;
        dst->slid               = src->slid;
@@ -141,4 +186,35 @@ void ib_copy_path_rec_from_user(struct ib_sa_path_rec *dst,
        dst->preference         = src->preference;
        dst->packet_life_time_selector = src->packet_life_time_selector;
 }
+
+void ib_copy_path_rec_from_user(struct ib_sa_path_rec *dst,
+                               struct ib_user_path_rec *src) {
+       memset(dst->dmac, 0, sizeof(dst->dmac));
+       memset(dst->smac, 0, sizeof(dst->smac));
+       dst->vlan = 0xFFFF;
+
+       ib_copy_path_rec_from_user_assign(dst, src);
+}
 EXPORT_SYMBOL(ib_copy_path_rec_from_user);
+
+void ib_copy_path_rec_from_user_ex(struct ib_sa_path_rec *dst,
+                                  struct ib_user_path_rec_ex *src) {
+       if (src->comp_mask & IB_USER_PATH_REC_ATTR_DMAC)
+               memcpy(dst->dmac, src->dmac, sizeof(dst->dmac));
+       else
+               memset(dst->dmac, 0, sizeof(dst->dmac));
+
+       if (src->comp_mask & IB_USER_PATH_REC_ATTR_SMAC)
+               memcpy(dst->smac, src->smac, sizeof(dst->smac));
+       else
+               memset(dst->smac, 0, sizeof(dst->smac));
+
+       if (src->comp_mask & IB_USER_PATH_REC_ATTR_VID)
+               dst->vlan = src->vlan;
+       else
+               dst->vlan = 0xFFFF;
+
+       ib_copy_path_rec_from_user_assign(dst, (struct ib_user_path_rec *)
+                                         UVERB_EX_TO_UVERB(src));
+}
+EXPORT_SYMBOL(ib_copy_path_rec_from_user_ex);
diff --git a/include/rdma/ib_marshall.h b/include/rdma/ib_marshall.h
index db03720..11ab3a8 100644
--- a/include/rdma/ib_marshall.h
+++ b/include/rdma/ib_marshall.h
@@ -41,13 +41,25 @@
 void ib_copy_qp_attr_to_user(struct ib_uverbs_qp_attr *dst,
                             struct ib_qp_attr *src);
 
+void ib_copy_qp_attr_to_user_ex(struct ib_uverbs_qp_attr_ex *dst,
+                               struct ib_qp_attr *src);
+
 void ib_copy_ah_attr_to_user(struct ib_uverbs_ah_attr *dst,
                             struct ib_ah_attr *src);
 
+void ib_copy_ah_attr_to_user_ex(struct ib_uverbs_ah_attr_ex *dst,
+                               struct ib_ah_attr *src);
+
 void ib_copy_path_rec_to_user(struct ib_user_path_rec *dst,
                              struct ib_sa_path_rec *src);
 
+void ib_copy_path_rec_to_user_ex(struct ib_user_path_rec_ex *dst,
+                                struct ib_sa_path_rec *src);
+
 void ib_copy_path_rec_from_user(struct ib_sa_path_rec *dst,
                                struct ib_user_path_rec *src);
 
+void ib_copy_path_rec_from_user_ex(struct ib_sa_path_rec *dst,
+                                  struct ib_user_path_rec_ex *src);
+
 #endif /* IB_USER_MARSHALL_H */
diff --git a/include/uapi/rdma/ib_user_sa.h b/include/uapi/rdma/ib_user_sa.h
index cfc7c9b..367d66a 100644
--- a/include/uapi/rdma/ib_user_sa.h
+++ b/include/uapi/rdma/ib_user_sa.h
@@ -48,7 +48,13 @@ enum {
 struct ib_path_rec_data {
        __u32   flags;
        __u32   reserved;
-       __u32   path_rec[16];
+       __u32   path_rec[20];
+};
+
+enum ibv_kern_path_rec_attr_mask {
+       IB_USER_PATH_REC_ATTR_DMAC = 1ULL << 0,
+       IB_USER_PATH_REC_ATTR_SMAC = 1ULL << 1,
+       IB_USER_PATH_REC_ATTR_VID  = 1ULL << 2
 };
 
 struct ib_user_path_rec {
@@ -73,4 +79,30 @@ struct ib_user_path_rec {
        __u8    preference;
 };
 
+struct ib_user_path_rec_ex {
+       __u32   comp_mask;
+       __u8    dgid[16];
+       __u8    sgid[16];
+       __be16  dlid;
+       __be16  slid;
+       __u32   raw_traffic;
+       __be32  flow_label;
+       __u32   reversible;
+       __u32   mtu;
+       __be16  pkey;
+       __u8    hop_limit;
+       __u8    traffic_class;
+       __u8    numb_path;
+       __u8    sl;
+       __u8    mtu_selector;
+       __u8    rate_selector;
+       __u8    rate;
+       __u8    packet_life_time_selector;
+       __u8    packet_life_time;
+       __u8    preference;
+       __u8    smac[6];
+       __u8    dmac[6];
+       __be16  vlan;
+};
+
 #endif /* IB_USER_SA_H */
diff --git a/include/uapi/rdma/ib_user_verbs.h 
b/include/uapi/rdma/ib_user_verbs.h
index 61535aa..954a790 100644
--- a/include/uapi/rdma/ib_user_verbs.h
+++ b/include/uapi/rdma/ib_user_verbs.h
@@ -86,7 +86,9 @@ enum {
        IB_USER_VERBS_CMD_OPEN_XRCD,
        IB_USER_VERBS_CMD_CLOSE_XRCD,
        IB_USER_VERBS_CMD_CREATE_XSRQ,
-       IB_USER_VERBS_CMD_OPEN_QP
+       IB_USER_VERBS_CMD_OPEN_QP,
+       IB_USER_VERBS_CMD_MODIFY_QP_EX = IB_USER_VERBS_CMD_THRESHOLD,
+       IB_USER_VERBS_CMD_CREATE_AH_EX,
 };
 
 /*
@@ -392,6 +394,25 @@ struct ib_uverbs_ah_attr {
        __u8  reserved;
 };
 
+enum ib_uverbs_ah_attr_mask {
+       IB_UVERBS_AH_ATTR_DMAC,
+       IB_UVERBS_AH_ATTR_VID
+};
+
+struct ib_uverbs_ah_attr_ex {
+       __u32 comp_mask;
+       struct ib_uverbs_global_route grh;
+       __u16 dlid;
+       __u8  sl;
+       __u8  src_path_bits;
+       __u8  static_rate;
+       __u8  is_global;
+       __u8  port_num;
+       __u8  reserved;
+       __u8  dmac[6];
+       __u16 vlan;
+};
+
 struct ib_uverbs_qp_attr {
        __u32   qp_attr_mask;
        __u32   qp_state;
@@ -430,6 +451,45 @@ struct ib_uverbs_qp_attr {
        __u8    reserved[5];
 };
 
+struct ib_uverbs_qp_attr_ex {
+       __u32   comp_mask;
+       __u32   qp_attr_mask;
+       __u32   qp_state;
+       __u32   cur_qp_state;
+       __u32   path_mtu;
+       __u32   path_mig_state;
+       __u32   qkey;
+       __u32   rq_psn;
+       __u32   sq_psn;
+       __u32   dest_qp_num;
+       __u32   qp_access_flags;
+
+       struct ib_uverbs_ah_attr_ex ah_attr;
+       struct ib_uverbs_ah_attr_ex alt_ah_attr;
+
+       /* ib_qp_cap */
+       __u32   max_send_wr;
+       __u32   max_recv_wr;
+       __u32   max_send_sge;
+       __u32   max_recv_sge;
+       __u32   max_inline_data;
+
+       __u16   pkey_index;
+       __u16   alt_pkey_index;
+       __u8    en_sqd_async_notify;
+       __u8    sq_draining;
+       __u8    max_rd_atomic;
+       __u8    max_dest_rd_atomic;
+       __u8    min_rnr_timer;
+       __u8    port_num;
+       __u8    timeout;
+       __u8    retry_cnt;
+       __u8    rnr_retry;
+       __u8    alt_port_num;
+       __u8    alt_timeout;
+       __u8    reserved[5];
+};
+
 struct ib_uverbs_create_qp {
        __u64 response;
        __u64 user_handle;
@@ -531,6 +591,17 @@ struct ib_uverbs_query_qp_resp {
        __u64 driver_data[0];
 };
 
+enum ib_uverbs_qp_dest_ex_comp_mask {
+       IBV_QP_DEST_EX_DMAC          = (1ULL << 0),
+       IBV_QP_DEST_EX_VID           = (1ULL << 1)
+};
+
+struct ib_uverbs_qp_dest_ex {
+       __u32 comp_mask;
+       __u8  dmac[6];
+       __u16 vid;
+};
+
 struct ib_uverbs_modify_qp {
        struct ib_uverbs_qp_dest dest;
        struct ib_uverbs_qp_dest alt_dest;
@@ -561,6 +632,44 @@ struct ib_uverbs_modify_qp {
        __u64 driver_data[0];
 };
 
+enum ib_uverbs_modify_qp_ex_comp_mask {
+       IB_UVERBS_MODIFY_QP_EX_DEST_EX_FLAGS          = (1ULL << 0),
+       IB_UVERBS_MODIFY_QP_EX_ALT_DEST_EX_FLAGS      = (1ULL << 1)
+};
+
+struct ib_uverbs_modify_qp_ex {
+       __u32 comp_mask;
+       struct ib_uverbs_qp_dest dest;
+       struct ib_uverbs_qp_dest alt_dest;
+       __u32 qp_handle;
+       __u32 attr_mask;
+       __u32 qkey;
+       __u32 rq_psn;
+       __u32 sq_psn;
+       __u32 dest_qp_num;
+       __u32 qp_access_flags;
+       __u16 pkey_index;
+       __u16 alt_pkey_index;
+       __u8  qp_state;
+       __u8  cur_qp_state;
+       __u8  path_mtu;
+       __u8  path_mig_state;
+       __u8  en_sqd_async_notify;
+       __u8  max_rd_atomic;
+       __u8  max_dest_rd_atomic;
+       __u8  min_rnr_timer;
+       __u8  port_num;
+       __u8  timeout;
+       __u8  retry_cnt;
+       __u8  rnr_retry;
+       __u8  alt_port_num;
+       __u8  alt_timeout;
+       __u8  reserved[2];
+       struct ib_uverbs_qp_dest_ex dest_ex;
+       struct ib_uverbs_qp_dest_ex alt_dest_ex;
+       __u64 driver_data[0];
+};
+
 struct ib_uverbs_modify_qp_resp {
 };
 
@@ -670,6 +779,15 @@ struct ib_uverbs_create_ah {
        struct ib_uverbs_ah_attr attr;
 };
 
+struct ib_uverbs_create_ah_ex {
+       int comp_mask;
+       __u64 response;
+       __u64 user_handle;
+       __u32 pd_handle;
+       __u32 reserved;
+       struct ib_uverbs_ah_attr_ex attr;
+};
+
 struct ib_uverbs_create_ah_resp {
        __u32 ah_handle;
 };
-- 
1.7.1

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

Reply via email to