IB/usnic: Add UDP support in usnic_ib_qp_grp.[hc]
authorUpinder Malhi <umalhi@cisco.com>
Thu, 9 Jan 2014 22:48:18 +0000 (14:48 -0800)
committerRoland Dreier <roland@purestorage.com>
Tue, 14 Jan 2014 08:44:44 +0000 (00:44 -0800)
UDP support for qp_grps/qps.

Signed-off-by: Upinder Malhi <umalhi@cisco.com>
Signed-off-by: Roland Dreier <roland@purestorage.com>
drivers/infiniband/hw/usnic/usnic_ib_qp_grp.c
drivers/infiniband/hw/usnic/usnic_ib_qp_grp.h

index 2b7e0a1a07b4ea51b42066e23545b6f457e960ce..d6667a198d0b5856d38d87ac86c49460b7ec1f06 100644 (file)
@@ -245,6 +245,80 @@ static void release_roce_custom_flow(struct usnic_ib_qp_grp_flow *qp_flow)
        kfree(qp_flow);
 }
 
+static struct usnic_ib_qp_grp_flow*
+create_udp_flow(struct usnic_ib_qp_grp *qp_grp,
+               struct usnic_transport_spec *trans_spec)
+{
+       struct socket *sock;
+       int sock_fd;
+       int err;
+       struct filter filter;
+       struct usnic_filter_action uaction;
+       struct usnic_ib_qp_grp_flow *qp_flow;
+       struct usnic_fwd_flow *flow;
+       enum usnic_transport_type trans_type;
+       uint32_t addr;
+       uint16_t port_num;
+       int proto;
+
+       trans_type = trans_spec->trans_type;
+       sock_fd = trans_spec->udp.sock_fd;
+
+       /* Get and check socket */
+       sock = usnic_transport_get_socket(sock_fd);
+       if (IS_ERR_OR_NULL(sock))
+               return ERR_CAST(sock);
+
+       err = usnic_transport_sock_get_addr(sock, &proto, &addr, &port_num);
+       if (err)
+               goto out_put_sock;
+
+       if (proto != IPPROTO_UDP) {
+               usnic_err("Protocol for fd %d is not UDP", sock_fd);
+               err = -EPERM;
+               goto out_put_sock;
+       }
+
+       /* Create flow */
+       usnic_fwd_init_udp_filter(&filter, addr, port_num);
+       err = init_filter_action(qp_grp, &uaction);
+       if (err)
+               goto out_put_sock;
+
+       flow = usnic_fwd_alloc_flow(qp_grp->ufdev, &filter, &uaction);
+       if (IS_ERR_OR_NULL(flow)) {
+               usnic_err("Unable to alloc flow failed with err %ld\n",
+                               PTR_ERR(flow));
+               err = (flow) ? PTR_ERR(flow) : -EFAULT;
+               goto out_put_sock;
+       }
+
+       /* Create qp_flow */
+       qp_flow = kzalloc(sizeof(*qp_flow), GFP_ATOMIC);
+       if (IS_ERR_OR_NULL(qp_flow)) {
+               err = (qp_flow) ? PTR_ERR(qp_flow) : -ENOMEM;
+               goto out_dealloc_flow;
+       }
+       qp_flow->flow = flow;
+       qp_flow->trans_type = trans_type;
+       qp_flow->udp.sock = sock;
+       qp_flow->qp_grp = qp_grp;
+       return qp_flow;
+
+out_dealloc_flow:
+       usnic_fwd_dealloc_flow(flow);
+out_put_sock:
+       usnic_transport_put_socket(sock);
+       return ERR_PTR(err);
+}
+
+static void release_udp_flow(struct usnic_ib_qp_grp_flow *qp_flow)
+{
+       usnic_fwd_dealloc_flow(qp_flow->flow);
+       usnic_transport_put_socket(qp_flow->udp.sock);
+       kfree(qp_flow);
+}
+
 static struct usnic_ib_qp_grp_flow*
 create_and_add_flow(struct usnic_ib_qp_grp *qp_grp,
                        struct usnic_transport_spec *trans_spec)
@@ -257,6 +331,9 @@ create_and_add_flow(struct usnic_ib_qp_grp *qp_grp,
        case USNIC_TRANSPORT_ROCE_CUSTOM:
                qp_flow = create_roce_custom_flow(qp_grp, trans_spec);
                break;
+       case USNIC_TRANSPORT_IPV4_UDP:
+               qp_flow = create_udp_flow(qp_grp, trans_spec);
+               break;
        default:
                usnic_err("Unsupported transport %u\n",
                                trans_spec->trans_type);
@@ -278,6 +355,9 @@ static void release_and_remove_flow(struct usnic_ib_qp_grp_flow *qp_flow)
        case USNIC_TRANSPORT_ROCE_CUSTOM:
                release_roce_custom_flow(qp_flow);
                break;
+       case USNIC_TRANSPORT_IPV4_UDP:
+               release_udp_flow(qp_flow);
+               break;
        default:
                WARN(1, "Unsupported transport %u\n",
                                qp_flow->trans_type);
@@ -544,11 +624,19 @@ static int qp_grp_id_from_flow(struct usnic_ib_qp_grp_flow *qp_flow,
                                uint32_t *id)
 {
        enum usnic_transport_type trans_type = qp_flow->trans_type;
+       int err;
 
        switch (trans_type) {
        case USNIC_TRANSPORT_ROCE_CUSTOM:
                *id = qp_flow->usnic_roce.port_num;
                break;
+       case USNIC_TRANSPORT_IPV4_UDP:
+               err = usnic_transport_sock_get_addr(qp_flow->udp.sock,
+                                                       NULL, NULL,
+                                                       (uint16_t *) id);
+               if (err)
+                       return err;
+               break;
        default:
                usnic_err("Unsupported transport %u\n", trans_type);
                return -EINVAL;
index 570fea2e2cb96ed24c66bf79fe43ed4d962f3c85..a8ba1b9224d8d4941eb19b23958d2ce5a8d7b4d7 100644 (file)
@@ -56,6 +56,9 @@ struct usnic_ib_qp_grp_flow {
                struct {
                        uint16_t        port_num;
                } usnic_roce;
+               struct {
+                       struct socket   *sock;
+               } udp;
        };
        struct usnic_ib_qp_grp          *qp_grp;
        struct list_head                link;
@@ -76,6 +79,14 @@ usnic_vnic_res_spec min_transport_spec[USNIC_TRANSPORT_MAX] = {
                        {.type = USNIC_VNIC_RES_TYPE_EOL,       .cnt = 0,},
                },
        },
+       { /*USNIC_TRANSPORT_IPV4_UDP*/
+               .resources = {
+                       {.type = USNIC_VNIC_RES_TYPE_WQ,        .cnt = 1,},
+                       {.type = USNIC_VNIC_RES_TYPE_RQ,        .cnt = 1,},
+                       {.type = USNIC_VNIC_RES_TYPE_CQ,        .cnt = 1,},
+                       {.type = USNIC_VNIC_RES_TYPE_EOL,       .cnt = 0,},
+               },
+       },
 };
 
 const char *usnic_ib_qp_grp_state_to_string(enum ib_qp_state state);