GNU Linux-libre 4.19.264-gnu1
[releases.git] / drivers / infiniband / hw / mlx5 / flow.c
1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2 /*
3  * Copyright (c) 2018, Mellanox Technologies inc.  All rights reserved.
4  */
5
6 #include <rdma/ib_user_verbs.h>
7 #include <rdma/ib_verbs.h>
8 #include <rdma/uverbs_types.h>
9 #include <rdma/uverbs_ioctl.h>
10 #include <rdma/mlx5_user_ioctl_cmds.h>
11 #include <rdma/ib_umem.h>
12 #include <linux/mlx5/driver.h>
13 #include <linux/mlx5/fs.h>
14 #include "mlx5_ib.h"
15
16 #define UVERBS_MODULE_NAME mlx5_ib
17 #include <rdma/uverbs_named_ioctl.h>
18
19 static const struct uverbs_attr_spec mlx5_ib_flow_type[] = {
20         [MLX5_IB_FLOW_TYPE_NORMAL] = {
21                 .type = UVERBS_ATTR_TYPE_PTR_IN,
22                 .u.ptr = {
23                         .len = sizeof(u16), /* data is priority */
24                         .min_len = sizeof(u16),
25                 }
26         },
27         [MLX5_IB_FLOW_TYPE_SNIFFER] = {
28                 .type = UVERBS_ATTR_TYPE_PTR_IN,
29                 UVERBS_ATTR_NO_DATA(),
30         },
31         [MLX5_IB_FLOW_TYPE_ALL_DEFAULT] = {
32                 .type = UVERBS_ATTR_TYPE_PTR_IN,
33                 UVERBS_ATTR_NO_DATA(),
34         },
35         [MLX5_IB_FLOW_TYPE_MC_DEFAULT] = {
36                 .type = UVERBS_ATTR_TYPE_PTR_IN,
37                 UVERBS_ATTR_NO_DATA(),
38         },
39 };
40
41 static int UVERBS_HANDLER(MLX5_IB_METHOD_CREATE_FLOW)(
42         struct ib_uverbs_file *file, struct uverbs_attr_bundle *attrs)
43 {
44         struct mlx5_ib_flow_handler *flow_handler;
45         struct mlx5_ib_flow_matcher *fs_matcher;
46         void *devx_obj;
47         int dest_id, dest_type;
48         void *cmd_in;
49         int inlen;
50         bool dest_devx, dest_qp;
51         struct ib_qp *qp = NULL;
52         struct ib_uobject *uobj =
53                 uverbs_attr_get_uobject(attrs, MLX5_IB_ATTR_CREATE_FLOW_HANDLE);
54         struct mlx5_ib_dev *dev = to_mdev(uobj->context->device);
55
56         if (!capable(CAP_NET_RAW))
57                 return -EPERM;
58
59         dest_devx =
60                 uverbs_attr_is_valid(attrs, MLX5_IB_ATTR_CREATE_FLOW_DEST_DEVX);
61         dest_qp = uverbs_attr_is_valid(attrs,
62                                        MLX5_IB_ATTR_CREATE_FLOW_DEST_QP);
63
64         if ((dest_devx && dest_qp) || (!dest_devx && !dest_qp))
65                 return -EINVAL;
66
67         if (dest_devx) {
68                 devx_obj = uverbs_attr_get_obj(
69                         attrs, MLX5_IB_ATTR_CREATE_FLOW_DEST_DEVX);
70                 if (IS_ERR(devx_obj))
71                         return PTR_ERR(devx_obj);
72
73                 /* Verify that the given DEVX object is a flow
74                  * steering destination.
75                  */
76                 if (!mlx5_ib_devx_is_flow_dest(devx_obj, &dest_id, &dest_type))
77                         return -EINVAL;
78         } else {
79                 struct mlx5_ib_qp *mqp;
80
81                 qp = uverbs_attr_get_obj(attrs,
82                                          MLX5_IB_ATTR_CREATE_FLOW_DEST_QP);
83                 if (IS_ERR(qp))
84                         return PTR_ERR(qp);
85
86                 if (qp->qp_type != IB_QPT_RAW_PACKET)
87                         return -EINVAL;
88
89                 mqp = to_mqp(qp);
90                 if (mqp->flags & MLX5_IB_QP_RSS)
91                         dest_id = mqp->rss_qp.tirn;
92                 else
93                         dest_id = mqp->raw_packet_qp.rq.tirn;
94                 dest_type = MLX5_FLOW_DESTINATION_TYPE_TIR;
95         }
96
97         if (dev->rep)
98                 return -ENOTSUPP;
99
100         cmd_in = uverbs_attr_get_alloced_ptr(
101                 attrs, MLX5_IB_ATTR_CREATE_FLOW_MATCH_VALUE);
102         inlen = uverbs_attr_get_len(attrs,
103                                     MLX5_IB_ATTR_CREATE_FLOW_MATCH_VALUE);
104         fs_matcher = uverbs_attr_get_obj(attrs,
105                                          MLX5_IB_ATTR_CREATE_FLOW_MATCHER);
106         flow_handler = mlx5_ib_raw_fs_rule_add(dev, fs_matcher, cmd_in, inlen,
107                                                dest_id, dest_type);
108         if (IS_ERR(flow_handler))
109                 return PTR_ERR(flow_handler);
110
111         ib_set_flow(uobj, &flow_handler->ibflow, qp, &dev->ib_dev);
112
113         return 0;
114 }
115
116 static int flow_matcher_cleanup(struct ib_uobject *uobject,
117                                 enum rdma_remove_reason why)
118 {
119         struct mlx5_ib_flow_matcher *obj = uobject->object;
120         int ret;
121
122         ret = ib_destroy_usecnt(&obj->usecnt, why, uobject);
123         if (ret)
124                 return ret;
125
126         kfree(obj);
127         return 0;
128 }
129
130 static int UVERBS_HANDLER(MLX5_IB_METHOD_FLOW_MATCHER_CREATE)(
131         struct ib_uverbs_file *file, struct uverbs_attr_bundle *attrs)
132 {
133         struct ib_uobject *uobj = uverbs_attr_get_uobject(
134                 attrs, MLX5_IB_ATTR_FLOW_MATCHER_CREATE_HANDLE);
135         struct mlx5_ib_dev *dev = to_mdev(uobj->context->device);
136         struct mlx5_ib_flow_matcher *obj;
137         int err;
138
139         obj = kzalloc(sizeof(struct mlx5_ib_flow_matcher), GFP_KERNEL);
140         if (!obj)
141                 return -ENOMEM;
142
143         obj->mask_len = uverbs_attr_get_len(
144                 attrs, MLX5_IB_ATTR_FLOW_MATCHER_MATCH_MASK);
145         err = uverbs_copy_from(&obj->matcher_mask,
146                                attrs,
147                                MLX5_IB_ATTR_FLOW_MATCHER_MATCH_MASK);
148         if (err)
149                 goto end;
150
151         obj->flow_type = uverbs_attr_get_enum_id(
152                 attrs, MLX5_IB_ATTR_FLOW_MATCHER_FLOW_TYPE);
153
154         if (obj->flow_type == MLX5_IB_FLOW_TYPE_NORMAL) {
155                 err = uverbs_copy_from(&obj->priority,
156                                        attrs,
157                                        MLX5_IB_ATTR_FLOW_MATCHER_FLOW_TYPE);
158                 if (err)
159                         goto end;
160         }
161
162         err = uverbs_copy_from(&obj->match_criteria_enable,
163                                attrs,
164                                MLX5_IB_ATTR_FLOW_MATCHER_MATCH_CRITERIA);
165         if (err)
166                 goto end;
167
168         uobj->object = obj;
169         obj->mdev = dev->mdev;
170         atomic_set(&obj->usecnt, 0);
171         return 0;
172
173 end:
174         kfree(obj);
175         return err;
176 }
177
178 DECLARE_UVERBS_NAMED_METHOD(
179         MLX5_IB_METHOD_CREATE_FLOW,
180         UVERBS_ATTR_IDR(MLX5_IB_ATTR_CREATE_FLOW_HANDLE,
181                         UVERBS_OBJECT_FLOW,
182                         UVERBS_ACCESS_NEW,
183                         UA_MANDATORY),
184         UVERBS_ATTR_PTR_IN(
185                 MLX5_IB_ATTR_CREATE_FLOW_MATCH_VALUE,
186                 UVERBS_ATTR_SIZE(1, sizeof(struct mlx5_ib_match_params)),
187                 UA_MANDATORY,
188                 UA_ALLOC_AND_COPY),
189         UVERBS_ATTR_IDR(MLX5_IB_ATTR_CREATE_FLOW_MATCHER,
190                         MLX5_IB_OBJECT_FLOW_MATCHER,
191                         UVERBS_ACCESS_READ,
192                         UA_MANDATORY),
193         UVERBS_ATTR_IDR(MLX5_IB_ATTR_CREATE_FLOW_DEST_QP,
194                         UVERBS_OBJECT_QP,
195                         UVERBS_ACCESS_READ),
196         UVERBS_ATTR_IDR(MLX5_IB_ATTR_CREATE_FLOW_DEST_DEVX,
197                         MLX5_IB_OBJECT_DEVX_OBJ,
198                         UVERBS_ACCESS_READ));
199
200 DECLARE_UVERBS_NAMED_METHOD_DESTROY(
201         MLX5_IB_METHOD_DESTROY_FLOW,
202         UVERBS_ATTR_IDR(MLX5_IB_ATTR_CREATE_FLOW_HANDLE,
203                         UVERBS_OBJECT_FLOW,
204                         UVERBS_ACCESS_DESTROY,
205                         UA_MANDATORY));
206
207 ADD_UVERBS_METHODS(mlx5_ib_fs,
208                    UVERBS_OBJECT_FLOW,
209                    &UVERBS_METHOD(MLX5_IB_METHOD_CREATE_FLOW),
210                    &UVERBS_METHOD(MLX5_IB_METHOD_DESTROY_FLOW));
211
212 DECLARE_UVERBS_NAMED_METHOD(
213         MLX5_IB_METHOD_FLOW_MATCHER_CREATE,
214         UVERBS_ATTR_IDR(MLX5_IB_ATTR_FLOW_MATCHER_CREATE_HANDLE,
215                         MLX5_IB_OBJECT_FLOW_MATCHER,
216                         UVERBS_ACCESS_NEW,
217                         UA_MANDATORY),
218         UVERBS_ATTR_PTR_IN(
219                 MLX5_IB_ATTR_FLOW_MATCHER_MATCH_MASK,
220                 UVERBS_ATTR_SIZE(1, sizeof(struct mlx5_ib_match_params)),
221                 UA_MANDATORY),
222         UVERBS_ATTR_ENUM_IN(MLX5_IB_ATTR_FLOW_MATCHER_FLOW_TYPE,
223                             mlx5_ib_flow_type,
224                             UA_MANDATORY),
225         UVERBS_ATTR_PTR_IN(MLX5_IB_ATTR_FLOW_MATCHER_MATCH_CRITERIA,
226                            UVERBS_ATTR_TYPE(u8),
227                            UA_MANDATORY));
228
229 DECLARE_UVERBS_NAMED_METHOD_DESTROY(
230         MLX5_IB_METHOD_FLOW_MATCHER_DESTROY,
231         UVERBS_ATTR_IDR(MLX5_IB_ATTR_FLOW_MATCHER_DESTROY_HANDLE,
232                         MLX5_IB_OBJECT_FLOW_MATCHER,
233                         UVERBS_ACCESS_DESTROY,
234                         UA_MANDATORY));
235
236 DECLARE_UVERBS_NAMED_OBJECT(MLX5_IB_OBJECT_FLOW_MATCHER,
237                             UVERBS_TYPE_ALLOC_IDR(flow_matcher_cleanup),
238                             &UVERBS_METHOD(MLX5_IB_METHOD_FLOW_MATCHER_CREATE),
239                             &UVERBS_METHOD(MLX5_IB_METHOD_FLOW_MATCHER_DESTROY));
240
241 DECLARE_UVERBS_OBJECT_TREE(flow_objects,
242                            &UVERBS_OBJECT(MLX5_IB_OBJECT_FLOW_MATCHER));
243
244 int mlx5_ib_get_flow_trees(const struct uverbs_object_tree_def **root)
245 {
246         int i = 0;
247
248         root[i++] = &flow_objects;
249         root[i++] = &mlx5_ib_fs;
250
251         return i;
252 }