aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/infiniband/core/uverbs.h3
-rw-r--r--drivers/infiniband/core/uverbs_cmd.c214
-rw-r--r--drivers/infiniband/core/uverbs_main.c13
-rw-r--r--include/rdma/ib_verbs.h1
-rw-r--r--include/uapi/rdma/ib_user_verbs.h89
5 files changed, 318 insertions, 2 deletions
diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h
index 0fcd7aa26fa2..ad9d1028102d 100644
--- a/drivers/infiniband/core/uverbs.h
+++ b/drivers/infiniband/core/uverbs.h
@@ -155,6 +155,7 @@ extern struct idr ib_uverbs_cq_idr;
155extern struct idr ib_uverbs_qp_idr; 155extern struct idr ib_uverbs_qp_idr;
156extern struct idr ib_uverbs_srq_idr; 156extern struct idr ib_uverbs_srq_idr;
157extern struct idr ib_uverbs_xrcd_idr; 157extern struct idr ib_uverbs_xrcd_idr;
158extern struct idr ib_uverbs_rule_idr;
158 159
159void idr_remove_uobj(struct idr *idp, struct ib_uobject *uobj); 160void idr_remove_uobj(struct idr *idp, struct ib_uobject *uobj);
160 161
@@ -215,5 +216,7 @@ IB_UVERBS_DECLARE_CMD(destroy_srq);
215IB_UVERBS_DECLARE_CMD(create_xsrq); 216IB_UVERBS_DECLARE_CMD(create_xsrq);
216IB_UVERBS_DECLARE_CMD(open_xrcd); 217IB_UVERBS_DECLARE_CMD(open_xrcd);
217IB_UVERBS_DECLARE_CMD(close_xrcd); 218IB_UVERBS_DECLARE_CMD(close_xrcd);
219IB_UVERBS_DECLARE_CMD(create_flow);
220IB_UVERBS_DECLARE_CMD(destroy_flow);
218 221
219#endif /* UVERBS_H */ 222#endif /* UVERBS_H */
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c
index b3c07b0c9f26..6e98df929e29 100644
--- a/drivers/infiniband/core/uverbs_cmd.c
+++ b/drivers/infiniband/core/uverbs_cmd.c
@@ -54,6 +54,7 @@ static struct uverbs_lock_class qp_lock_class = { .name = "QP-uobj" };
54static struct uverbs_lock_class ah_lock_class = { .name = "AH-uobj" }; 54static struct uverbs_lock_class ah_lock_class = { .name = "AH-uobj" };
55static struct uverbs_lock_class srq_lock_class = { .name = "SRQ-uobj" }; 55static struct uverbs_lock_class srq_lock_class = { .name = "SRQ-uobj" };
56static struct uverbs_lock_class xrcd_lock_class = { .name = "XRCD-uobj" }; 56static struct uverbs_lock_class xrcd_lock_class = { .name = "XRCD-uobj" };
57static struct uverbs_lock_class rule_lock_class = { .name = "RULE-uobj" };
57 58
58#define INIT_UDATA(udata, ibuf, obuf, ilen, olen) \ 59#define INIT_UDATA(udata, ibuf, obuf, ilen, olen) \
59 do { \ 60 do { \
@@ -330,6 +331,7 @@ ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file,
330 INIT_LIST_HEAD(&ucontext->srq_list); 331 INIT_LIST_HEAD(&ucontext->srq_list);
331 INIT_LIST_HEAD(&ucontext->ah_list); 332 INIT_LIST_HEAD(&ucontext->ah_list);
332 INIT_LIST_HEAD(&ucontext->xrcd_list); 333 INIT_LIST_HEAD(&ucontext->xrcd_list);
334 INIT_LIST_HEAD(&ucontext->rule_list);
333 ucontext->closing = 0; 335 ucontext->closing = 0;
334 336
335 resp.num_comp_vectors = file->device->num_comp_vectors; 337 resp.num_comp_vectors = file->device->num_comp_vectors;
@@ -2587,6 +2589,218 @@ out_put:
2587 return ret ? ret : in_len; 2589 return ret ? ret : in_len;
2588} 2590}
2589 2591
2592static int kern_spec_to_ib_spec(struct ib_kern_spec *kern_spec,
2593 union ib_flow_spec *ib_spec)
2594{
2595 ib_spec->type = kern_spec->type;
2596
2597 switch (ib_spec->type) {
2598 case IB_FLOW_SPEC_ETH:
2599 ib_spec->eth.size = sizeof(struct ib_flow_spec_eth);
2600 if (ib_spec->eth.size != kern_spec->eth.size)
2601 return -EINVAL;
2602 memcpy(&ib_spec->eth.val, &kern_spec->eth.val,
2603 sizeof(struct ib_flow_eth_filter));
2604 memcpy(&ib_spec->eth.mask, &kern_spec->eth.mask,
2605 sizeof(struct ib_flow_eth_filter));
2606 break;
2607 case IB_FLOW_SPEC_IPV4:
2608 ib_spec->ipv4.size = sizeof(struct ib_flow_spec_ipv4);
2609 if (ib_spec->ipv4.size != kern_spec->ipv4.size)
2610 return -EINVAL;
2611 memcpy(&ib_spec->ipv4.val, &kern_spec->ipv4.val,
2612 sizeof(struct ib_flow_ipv4_filter));
2613 memcpy(&ib_spec->ipv4.mask, &kern_spec->ipv4.mask,
2614 sizeof(struct ib_flow_ipv4_filter));
2615 break;
2616 case IB_FLOW_SPEC_TCP:
2617 case IB_FLOW_SPEC_UDP:
2618 ib_spec->tcp_udp.size = sizeof(struct ib_flow_spec_tcp_udp);
2619 if (ib_spec->tcp_udp.size != kern_spec->tcp_udp.size)
2620 return -EINVAL;
2621 memcpy(&ib_spec->tcp_udp.val, &kern_spec->tcp_udp.val,
2622 sizeof(struct ib_flow_tcp_udp_filter));
2623 memcpy(&ib_spec->tcp_udp.mask, &kern_spec->tcp_udp.mask,
2624 sizeof(struct ib_flow_tcp_udp_filter));
2625 break;
2626 default:
2627 return -EINVAL;
2628 }
2629 return 0;
2630}
2631
2632ssize_t ib_uverbs_create_flow(struct ib_uverbs_file *file,
2633 const char __user *buf, int in_len,
2634 int out_len)
2635{
2636 struct ib_uverbs_create_flow cmd;
2637 struct ib_uverbs_create_flow_resp resp;
2638 struct ib_uobject *uobj;
2639 struct ib_flow *flow_id;
2640 struct ib_kern_flow_attr *kern_flow_attr;
2641 struct ib_flow_attr *flow_attr;
2642 struct ib_qp *qp;
2643 int err = 0;
2644 void *kern_spec;
2645 void *ib_spec;
2646 int i;
2647 int kern_attr_size;
2648
2649 if (out_len < sizeof(resp))
2650 return -ENOSPC;
2651
2652 if (copy_from_user(&cmd, buf, sizeof(cmd)))
2653 return -EFAULT;
2654
2655 if ((cmd.flow_attr.type == IB_FLOW_ATTR_SNIFFER &&
2656 !capable(CAP_NET_ADMIN)) || !capable(CAP_NET_RAW))
2657 return -EPERM;
2658
2659 if (cmd.flow_attr.num_of_specs) {
2660 kern_flow_attr = kmalloc(cmd.flow_attr.size, GFP_KERNEL);
2661 if (!kern_flow_attr)
2662 return -ENOMEM;
2663
2664 memcpy(kern_flow_attr, &cmd.flow_attr, sizeof(*kern_flow_attr));
2665 kern_attr_size = cmd.flow_attr.size - sizeof(cmd) - sizeof(struct ib_uverbs_cmd_hdr_ex);
2666 if (copy_from_user(kern_flow_attr + 1, buf + sizeof(cmd),
2667 kern_attr_size)) {
2668 err = -EFAULT;
2669 goto err_free_attr;
2670 }
2671 } else {
2672 kern_flow_attr = &cmd.flow_attr;
2673 kern_attr_size = sizeof(cmd.flow_attr);
2674 }
2675
2676 uobj = kmalloc(sizeof(*uobj), GFP_KERNEL);
2677 if (!uobj) {
2678 err = -ENOMEM;
2679 goto err_free_attr;
2680 }
2681 init_uobj(uobj, 0, file->ucontext, &rule_lock_class);
2682 down_write(&uobj->mutex);
2683
2684 qp = idr_read_qp(cmd.qp_handle, file->ucontext);
2685 if (!qp) {
2686 err = -EINVAL;
2687 goto err_uobj;
2688 }
2689
2690 flow_attr = kmalloc(cmd.flow_attr.size, GFP_KERNEL);
2691 if (!flow_attr) {
2692 err = -ENOMEM;
2693 goto err_put;
2694 }
2695
2696 flow_attr->type = kern_flow_attr->type;
2697 flow_attr->priority = kern_flow_attr->priority;
2698 flow_attr->num_of_specs = kern_flow_attr->num_of_specs;
2699 flow_attr->port = kern_flow_attr->port;
2700 flow_attr->flags = kern_flow_attr->flags;
2701 flow_attr->size = sizeof(*flow_attr);
2702
2703 kern_spec = kern_flow_attr + 1;
2704 ib_spec = flow_attr + 1;
2705 for (i = 0; i < flow_attr->num_of_specs && kern_attr_size > 0; i++) {
2706 err = kern_spec_to_ib_spec(kern_spec, ib_spec);
2707 if (err)
2708 goto err_free;
2709 flow_attr->size +=
2710 ((union ib_flow_spec *) ib_spec)->size;
2711 kern_attr_size -= ((struct ib_kern_spec *) kern_spec)->size;
2712 kern_spec += ((struct ib_kern_spec *) kern_spec)->size;
2713 ib_spec += ((union ib_flow_spec *) ib_spec)->size;
2714 }
2715 if (kern_attr_size) {
2716 pr_warn("create flow failed, %d bytes left from uverb cmd\n",
2717 kern_attr_size);
2718 goto err_free;
2719 }
2720 flow_id = ib_create_flow(qp, flow_attr, IB_FLOW_DOMAIN_USER);
2721 if (IS_ERR(flow_id)) {
2722 err = PTR_ERR(flow_id);
2723 goto err_free;
2724 }
2725 flow_id->qp = qp;
2726 flow_id->uobject = uobj;
2727 uobj->object = flow_id;
2728
2729 err = idr_add_uobj(&ib_uverbs_rule_idr, uobj);
2730 if (err)
2731 goto destroy_flow;
2732
2733 memset(&resp, 0, sizeof(resp));
2734 resp.flow_handle = uobj->id;
2735
2736 if (copy_to_user((void __user *)(unsigned long) cmd.response,
2737 &resp, sizeof(resp))) {
2738 err = -EFAULT;
2739 goto err_copy;
2740 }
2741
2742 put_qp_read(qp);
2743 mutex_lock(&file->mutex);
2744 list_add_tail(&uobj->list, &file->ucontext->rule_list);
2745 mutex_unlock(&file->mutex);
2746
2747 uobj->live = 1;
2748
2749 up_write(&uobj->mutex);
2750 kfree(flow_attr);
2751 if (cmd.flow_attr.num_of_specs)
2752 kfree(kern_flow_attr);
2753 return in_len;
2754err_copy:
2755 idr_remove_uobj(&ib_uverbs_rule_idr, uobj);
2756destroy_flow:
2757 ib_destroy_flow(flow_id);
2758err_free:
2759 kfree(flow_attr);
2760err_put:
2761 put_qp_read(qp);
2762err_uobj:
2763 put_uobj_write(uobj);
2764err_free_attr:
2765 if (cmd.flow_attr.num_of_specs)
2766 kfree(kern_flow_attr);
2767 return err;
2768}
2769
2770ssize_t ib_uverbs_destroy_flow(struct ib_uverbs_file *file,
2771 const char __user *buf, int in_len,
2772 int out_len) {
2773 struct ib_uverbs_destroy_flow cmd;
2774 struct ib_flow *flow_id;
2775 struct ib_uobject *uobj;
2776 int ret;
2777
2778 if (copy_from_user(&cmd, buf, sizeof(cmd)))
2779 return -EFAULT;
2780
2781 uobj = idr_write_uobj(&ib_uverbs_rule_idr, cmd.flow_handle,
2782 file->ucontext);
2783 if (!uobj)
2784 return -EINVAL;
2785 flow_id = uobj->object;
2786
2787 ret = ib_destroy_flow(flow_id);
2788 if (!ret)
2789 uobj->live = 0;
2790
2791 put_uobj_write(uobj);
2792
2793 idr_remove_uobj(&ib_uverbs_rule_idr, uobj);
2794
2795 mutex_lock(&file->mutex);
2796 list_del(&uobj->list);
2797 mutex_unlock(&file->mutex);
2798
2799 put_uobj(uobj);
2800
2801 return ret ? ret : in_len;
2802}
2803
2590static int __uverbs_create_xsrq(struct ib_uverbs_file *file, 2804static int __uverbs_create_xsrq(struct ib_uverbs_file *file,
2591 struct ib_uverbs_create_xsrq *cmd, 2805 struct ib_uverbs_create_xsrq *cmd,
2592 struct ib_udata *udata) 2806 struct ib_udata *udata)
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c
index e4e7b2449d19..75ad86c4abf8 100644
--- a/drivers/infiniband/core/uverbs_main.c
+++ b/drivers/infiniband/core/uverbs_main.c
@@ -73,6 +73,7 @@ DEFINE_IDR(ib_uverbs_cq_idr);
73DEFINE_IDR(ib_uverbs_qp_idr); 73DEFINE_IDR(ib_uverbs_qp_idr);
74DEFINE_IDR(ib_uverbs_srq_idr); 74DEFINE_IDR(ib_uverbs_srq_idr);
75DEFINE_IDR(ib_uverbs_xrcd_idr); 75DEFINE_IDR(ib_uverbs_xrcd_idr);
76DEFINE_IDR(ib_uverbs_rule_idr);
76 77
77static DEFINE_SPINLOCK(map_lock); 78static DEFINE_SPINLOCK(map_lock);
78static DECLARE_BITMAP(dev_map, IB_UVERBS_MAX_DEVICES); 79static DECLARE_BITMAP(dev_map, IB_UVERBS_MAX_DEVICES);
@@ -113,7 +114,9 @@ static ssize_t (*uverbs_cmd_table[])(struct ib_uverbs_file *file,
113 [IB_USER_VERBS_CMD_OPEN_XRCD] = ib_uverbs_open_xrcd, 114 [IB_USER_VERBS_CMD_OPEN_XRCD] = ib_uverbs_open_xrcd,
114 [IB_USER_VERBS_CMD_CLOSE_XRCD] = ib_uverbs_close_xrcd, 115 [IB_USER_VERBS_CMD_CLOSE_XRCD] = ib_uverbs_close_xrcd,
115 [IB_USER_VERBS_CMD_CREATE_XSRQ] = ib_uverbs_create_xsrq, 116 [IB_USER_VERBS_CMD_CREATE_XSRQ] = ib_uverbs_create_xsrq,
116 [IB_USER_VERBS_CMD_OPEN_QP] = ib_uverbs_open_qp 117 [IB_USER_VERBS_CMD_OPEN_QP] = ib_uverbs_open_qp,
118 [IB_USER_VERBS_CMD_CREATE_FLOW] = ib_uverbs_create_flow,
119 [IB_USER_VERBS_CMD_DESTROY_FLOW] = ib_uverbs_destroy_flow
117}; 120};
118 121
119static void ib_uverbs_add_one(struct ib_device *device); 122static void ib_uverbs_add_one(struct ib_device *device);
@@ -212,6 +215,14 @@ static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file,
212 kfree(uobj); 215 kfree(uobj);
213 } 216 }
214 217
218 list_for_each_entry_safe(uobj, tmp, &context->rule_list, list) {
219 struct ib_flow *flow_id = uobj->object;
220
221 idr_remove_uobj(&ib_uverbs_rule_idr, uobj);
222 ib_destroy_flow(flow_id);
223 kfree(uobj);
224 }
225
215 list_for_each_entry_safe(uobj, tmp, &context->qp_list, list) { 226 list_for_each_entry_safe(uobj, tmp, &context->qp_list, list) {
216 struct ib_qp *qp = uobj->object; 227 struct ib_qp *qp = uobj->object;
217 struct ib_uqp_object *uqp = 228 struct ib_uqp_object *uqp =
diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h
index 6f874b00491a..274205d4df97 100644
--- a/include/rdma/ib_verbs.h
+++ b/include/rdma/ib_verbs.h
@@ -954,6 +954,7 @@ struct ib_ucontext {
954 struct list_head srq_list; 954 struct list_head srq_list;
955 struct list_head ah_list; 955 struct list_head ah_list;
956 struct list_head xrcd_list; 956 struct list_head xrcd_list;
957 struct list_head rule_list;
957 int closing; 958 int closing;
958}; 959};
959 960
diff --git a/include/uapi/rdma/ib_user_verbs.h b/include/uapi/rdma/ib_user_verbs.h
index 61535aa0a62e..0b233c56b0e4 100644
--- a/include/uapi/rdma/ib_user_verbs.h
+++ b/include/uapi/rdma/ib_user_verbs.h
@@ -86,7 +86,9 @@ enum {
86 IB_USER_VERBS_CMD_OPEN_XRCD, 86 IB_USER_VERBS_CMD_OPEN_XRCD,
87 IB_USER_VERBS_CMD_CLOSE_XRCD, 87 IB_USER_VERBS_CMD_CLOSE_XRCD,
88 IB_USER_VERBS_CMD_CREATE_XSRQ, 88 IB_USER_VERBS_CMD_CREATE_XSRQ,
89 IB_USER_VERBS_CMD_OPEN_QP 89 IB_USER_VERBS_CMD_OPEN_QP,
90 IB_USER_VERBS_CMD_CREATE_FLOW = IB_USER_VERBS_CMD_THRESHOLD,
91 IB_USER_VERBS_CMD_DESTROY_FLOW
90}; 92};
91 93
92/* 94/*
@@ -694,6 +696,91 @@ struct ib_uverbs_detach_mcast {
694 __u64 driver_data[0]; 696 __u64 driver_data[0];
695}; 697};
696 698
699struct ib_kern_eth_filter {
700 __u8 dst_mac[6];
701 __u8 src_mac[6];
702 __be16 ether_type;
703 __be16 vlan_tag;
704};
705
706struct ib_kern_spec_eth {
707 __u32 type;
708 __u16 size;
709 __u16 reserved;
710 struct ib_kern_eth_filter val;
711 struct ib_kern_eth_filter mask;
712};
713
714struct ib_kern_ipv4_filter {
715 __be32 src_ip;
716 __be32 dst_ip;
717};
718
719struct ib_kern_spec_ipv4 {
720 __u32 type;
721 __u16 size;
722 __u16 reserved;
723 struct ib_kern_ipv4_filter val;
724 struct ib_kern_ipv4_filter mask;
725};
726
727struct ib_kern_tcp_udp_filter {
728 __be16 dst_port;
729 __be16 src_port;
730};
731
732struct ib_kern_spec_tcp_udp {
733 __u32 type;
734 __u16 size;
735 __u16 reserved;
736 struct ib_kern_tcp_udp_filter val;
737 struct ib_kern_tcp_udp_filter mask;
738};
739
740struct ib_kern_spec {
741 union {
742 struct {
743 __u32 type;
744 __u16 size;
745 __u16 reserved;
746 };
747 struct ib_kern_spec_eth eth;
748 struct ib_kern_spec_ipv4 ipv4;
749 struct ib_kern_spec_tcp_udp tcp_udp;
750 };
751};
752
753struct ib_kern_flow_attr {
754 __u32 type;
755 __u16 size;
756 __u16 priority;
757 __u8 num_of_specs;
758 __u8 reserved[2];
759 __u8 port;
760 __u32 flags;
761 /* Following are the optional layers according to user request
762 * struct ib_flow_spec_xxx
763 * struct ib_flow_spec_yyy
764 */
765};
766
767struct ib_uverbs_create_flow {
768 __u32 comp_mask;
769 __u64 response;
770 __u32 qp_handle;
771 struct ib_kern_flow_attr flow_attr;
772};
773
774struct ib_uverbs_create_flow_resp {
775 __u32 comp_mask;
776 __u32 flow_handle;
777};
778
779struct ib_uverbs_destroy_flow {
780 __u32 comp_mask;
781 __u32 flow_handle;
782};
783
697struct ib_uverbs_create_srq { 784struct ib_uverbs_create_srq {
698 __u64 response; 785 __u64 response;
699 __u64 user_handle; 786 __u64 user_handle;