IB/hfi1: Check P_KEY for all sent packets from user mode
authorSebastian Sanchez <sebastian.sanchez@intel.com>
Tue, 12 Apr 2016 18:22:21 +0000 (11:22 -0700)
committerDoug Ledford <dledford@redhat.com>
Thu, 28 Apr 2016 20:32:27 +0000 (16:32 -0400)
Add the P_KEY check for user-context mechanism for
both PIO and SDMA. For PIO, the
SendCtxtCheckEnable.DisallowKDETHPackets is set by
default. When the P_KEY is set,
SendCtxtCheckEnable.DisallowKDETHPackets is cleared.
For SDMA, a software check was included. This change
requires user processes to set the P_KEY before sending
any packets, otherwise, the sent packet will fail. The
original submission didn't have this check but it's
required.

Reviewed-by: Dean Luick <dean.luick@intel.com>
Reviewed-by: Dennis Dalessandro <dennis.dalessandro@intel.com>
Reviewed-by: Mikto Haralanov <mitko.haralanov@intel.com>
Signed-off-by: Sebastian Sanchez <sebastian.sanchez@intel.com>
Signed-off-by: Doug Ledford <dledford@redhat.com>
drivers/staging/rdma/hfi1/chip.c
drivers/staging/rdma/hfi1/hfi.h
drivers/staging/rdma/hfi1/user_sdma.c
drivers/staging/rdma/hfi1/verbs.c

index 56753c65b6145b096ddb0e852a4d3d9d14a227d5..b0a0a0d2cbad2f9d2825f44a0d0b05e406dbe99b 100644 (file)
@@ -13751,6 +13751,7 @@ int hfi1_set_ctxt_pkey(struct hfi1_devdata *dd, unsigned ctxt, u16 pkey)
        write_kctxt_csr(dd, sctxt, SEND_CTXT_CHECK_PARTITION_KEY, reg);
        reg = read_kctxt_csr(dd, sctxt, SEND_CTXT_CHECK_ENABLE);
        reg |= SEND_CTXT_CHECK_ENABLE_CHECK_PARTITION_KEY_SMASK;
+       reg &= ~SEND_CTXT_CHECK_ENABLE_DISALLOW_KDETH_PACKETS_SMASK;
        write_kctxt_csr(dd, sctxt, SEND_CTXT_CHECK_ENABLE, reg);
 done:
        return ret;
index ff04593eabe2ebf29db9e43e97c5bf9c73edc337..b1d4f605c14dbde874f434bf1daeb3e13dfdba64 100644 (file)
@@ -1333,6 +1333,9 @@ void process_becn(struct hfi1_pportdata *ppd, u8 sl,  u16 rlid, u32 lqpn,
 void return_cnp(struct hfi1_ibport *ibp, struct rvt_qp *qp, u32 remote_qpn,
                u32 pkey, u32 slid, u32 dlid, u8 sc5,
                const struct ib_grh *old_grh);
+#define PKEY_CHECK_INVALID -1
+int egress_pkey_check(struct hfi1_pportdata *ppd, __be16 *lrh, __be32 *bth,
+                     u8 sc5, int8_t s_pkey_index);
 
 #define PACKET_EGRESS_TIMEOUT 350
 static inline void pause_for_credit_return(struct hfi1_devdata *dd)
@@ -1776,6 +1779,7 @@ extern struct mutex hfi1_mutex;
 
 #define HFI1_PKT_USER_SC_INTEGRITY                                         \
        (SEND_CTXT_CHECK_ENABLE_DISALLOW_NON_KDETH_PACKETS_SMASK            \
+       | SEND_CTXT_CHECK_ENABLE_DISALLOW_KDETH_PACKETS_SMASK           \
        | SEND_CTXT_CHECK_ENABLE_DISALLOW_BYPASS_SMASK              \
        | SEND_CTXT_CHECK_ENABLE_DISALLOW_GRH_SMASK)
 
index 635ddf8b406dc1a2673aa9876b13e6981ec45411..0014c9c0e967a502c3623fbb1c242ec9f6d34102 100644 (file)
@@ -600,6 +600,13 @@ int hfi1_user_sdma_process_request(struct file *fp, struct iovec *iovec,
                goto free_req;
        }
 
+       /* Checking P_KEY for requests from user-space */
+       if (egress_pkey_check(dd->pport, req->hdr.lrh, req->hdr.bth, sc,
+                             PKEY_CHECK_INVALID)) {
+               ret = -EINVAL;
+               goto free_req;
+       }
+
        /*
         * Also should check the BTH.lnh. If it says the next header is GRH then
         * the RXE parsing will be off and will land in the middle of the KDETH
index 89f2aad45c1b8cfdb27d81aac73c2cd2ebd0c52f..c56c0cb0de80e1a089934558829ead542ada2a10 100644 (file)
@@ -1089,16 +1089,16 @@ bail:
 
 /*
  * egress_pkey_matches_entry - return 1 if the pkey matches ent (ent
- * being an entry from the ingress partition key table), return 0
+ * being an entry from the partition key table), return 0
  * otherwise. Use the matching criteria for egress partition keys
  * specified in the OPAv1 spec., section 9.1l.7.
  */
 static inline int egress_pkey_matches_entry(u16 pkey, u16 ent)
 {
        u16 mkey = pkey & PKEY_LOW_15_MASK;
-       u16 ment = ent & PKEY_LOW_15_MASK;
+       u16 mentry = ent & PKEY_LOW_15_MASK;
 
-       if (mkey == ment) {
+       if (mkey == mentry) {
                /*
                 * If pkey[15] is set (full partition member),
                 * is bit 15 in the corresponding table element
@@ -1111,32 +1111,32 @@ static inline int egress_pkey_matches_entry(u16 pkey, u16 ent)
        return 0;
 }
 
-/*
- * egress_pkey_check - return 0 if hdr's pkey matches according to the
- * criteria in the OPAv1 spec., section 9.11.7.
+/**
+ * egress_pkey_check - check P_KEY of a packet
+ * @ppd:    Physical IB port data
+ * @lrh: Local route header
+ * @bth: Base transport header
+ * @sc5:    SC for packet
+ * @s_pkey_index: It will be used for look up optimization for kernel contexts
+ * only. If it is negative value, then it means user contexts is calling this
+ * function.
+ *
+ * It checks if hdr's pkey is valid.
+ *
+ * Return: 0 on success, otherwise, 1
  */
-static inline int egress_pkey_check(struct hfi1_pportdata *ppd,
-                                   struct hfi1_ib_header *hdr,
-                                   struct rvt_qp *qp)
+int egress_pkey_check(struct hfi1_pportdata *ppd, __be16 *lrh, __be32 *bth,
+                     u8 sc5, int8_t s_pkey_index)
 {
-       struct hfi1_qp_priv *priv = qp->priv;
-       struct hfi1_other_headers *ohdr;
        struct hfi1_devdata *dd;
-       int i = 0;
+       int i;
        u16 pkey;
-       u8 lnh, sc5 = priv->s_sc;
+       int is_user_ctxt_mechanism = (s_pkey_index < 0);
 
        if (!(ppd->part_enforce & HFI1_PART_ENFORCE_OUT))
                return 0;
 
-       /* locate the pkey within the headers */
-       lnh = be16_to_cpu(hdr->lrh[0]) & 3;
-       if (lnh == HFI1_LRH_GRH)
-               ohdr = &hdr->u.l.oth;
-       else
-               ohdr = &hdr->u.oth;
-
-       pkey = (u16)be32_to_cpu(ohdr->bth[0]);
+       pkey = (u16)be32_to_cpu(bth[0]);
 
        /* If SC15, pkey[0:14] must be 0x7fff */
        if ((sc5 == 0xf) && ((pkey & PKEY_LOW_15_MASK) != PKEY_LOW_15_MASK))
@@ -1146,28 +1146,37 @@ static inline int egress_pkey_check(struct hfi1_pportdata *ppd,
        if ((pkey & PKEY_LOW_15_MASK) == 0)
                goto bad;
 
-       /* The most likely matching pkey has index qp->s_pkey_index */
-       if (unlikely(!egress_pkey_matches_entry(pkey,
-                                               ppd->pkeys
-                                               [qp->s_pkey_index]))) {
-               /* no match - try the entire table */
-               for (; i < MAX_PKEY_VALUES; i++) {
-                       if (egress_pkey_matches_entry(pkey, ppd->pkeys[i]))
-                               break;
-               }
+       /*
+        * For the kernel contexts only, if a qp is passed into the function,
+        * the most likely matching pkey has index qp->s_pkey_index
+        */
+       if (!is_user_ctxt_mechanism &&
+           egress_pkey_matches_entry(pkey, ppd->pkeys[s_pkey_index])) {
+               return 0;
        }
 
-       if (i < MAX_PKEY_VALUES)
-               return 0;
+       for (i = 0; i < MAX_PKEY_VALUES; i++) {
+               if (egress_pkey_matches_entry(pkey, ppd->pkeys[i]))
+                       return 0;
+       }
 bad:
-       incr_cntr64(&ppd->port_xmit_constraint_errors);
-       dd = ppd->dd;
-       if (!(dd->err_info_xmit_constraint.status & OPA_EI_STATUS_SMASK)) {
-               u16 slid = be16_to_cpu(hdr->lrh[3]);
-
-               dd->err_info_xmit_constraint.status |= OPA_EI_STATUS_SMASK;
-               dd->err_info_xmit_constraint.slid = slid;
-               dd->err_info_xmit_constraint.pkey = pkey;
+       /*
+        * For the user-context mechanism, the P_KEY check would only happen
+        * once per SDMA request, not once per packet.  Therefore, there's no
+        * need to increment the counter for the user-context mechanism.
+        */
+       if (!is_user_ctxt_mechanism) {
+               incr_cntr64(&ppd->port_xmit_constraint_errors);
+               dd = ppd->dd;
+               if (!(dd->err_info_xmit_constraint.status &
+                     OPA_EI_STATUS_SMASK)) {
+                       u16 slid = be16_to_cpu(lrh[3]);
+
+                       dd->err_info_xmit_constraint.status |=
+                               OPA_EI_STATUS_SMASK;
+                       dd->err_info_xmit_constraint.slid = slid;
+                       dd->err_info_xmit_constraint.pkey = pkey;
+               }
        }
        return 1;
 }
@@ -1227,11 +1236,26 @@ int hfi1_verbs_send(struct rvt_qp *qp, struct hfi1_pkt_state *ps)
 {
        struct hfi1_devdata *dd = dd_from_ibdev(qp->ibqp.device);
        struct hfi1_qp_priv *priv = qp->priv;
+       struct hfi1_other_headers *ohdr;
+       struct hfi1_ib_header *hdr;
        send_routine sr;
        int ret;
+       u8 lnh;
+
+       hdr = &ps->s_txreq->phdr.hdr;
+       /* locate the pkey within the headers */
+       lnh = be16_to_cpu(hdr->lrh[0]) & 3;
+       if (lnh == HFI1_LRH_GRH)
+               ohdr = &hdr->u.l.oth;
+       else
+               ohdr = &hdr->u.oth;
 
        sr = get_send_routine(qp, ps->s_txreq);
-       ret = egress_pkey_check(dd->pport, &ps->s_txreq->phdr.hdr, qp);
+       ret = egress_pkey_check(dd->pport,
+                               hdr->lrh,
+                               ohdr->bth,
+                               priv->s_sc,
+                               qp->s_pkey_index);
        if (unlikely(ret)) {
                /*
                 * The value we are returning here does not get propagated to