root/drivers/infiniband/core/uverbs_std_types_flow_action.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. uverbs_free_flow_action
  2. esp_flags_uverbs_to_verbs
  3. validate_flow_action_esp_keymat_aes_gcm
  4. flow_action_esp_replay_none
  5. flow_action_esp_replay_def_ok
  6. parse_esp_ip
  7. flow_action_esp_get_encap
  8. parse_flow_action_esp
  9. UVERBS_HANDLER
  10. UVERBS_HANDLER

   1 /*
   2  * Copyright (c) 2018, Mellanox Technologies inc.  All rights reserved.
   3  *
   4  * This software is available to you under a choice of one of two
   5  * licenses.  You may choose to be licensed under the terms of the GNU
   6  * General Public License (GPL) Version 2, available from the file
   7  * COPYING in the main directory of this source tree, or the
   8  * OpenIB.org BSD license below:
   9  *
  10  *     Redistribution and use in source and binary forms, with or
  11  *     without modification, are permitted provided that the following
  12  *     conditions are met:
  13  *
  14  *      - Redistributions of source code must retain the above
  15  *        copyright notice, this list of conditions and the following
  16  *        disclaimer.
  17  *
  18  *      - Redistributions in binary form must reproduce the above
  19  *        copyright notice, this list of conditions and the following
  20  *        disclaimer in the documentation and/or other materials
  21  *        provided with the distribution.
  22  *
  23  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  24  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  25  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  26  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  27  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  28  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  29  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  30  * SOFTWARE.
  31  */
  32 
  33 #include "rdma_core.h"
  34 #include "uverbs.h"
  35 #include <rdma/uverbs_std_types.h>
  36 
  37 static int uverbs_free_flow_action(struct ib_uobject *uobject,
  38                                    enum rdma_remove_reason why,
  39                                    struct uverbs_attr_bundle *attrs)
  40 {
  41         struct ib_flow_action *action = uobject->object;
  42         int ret;
  43 
  44         ret = ib_destroy_usecnt(&action->usecnt, why, uobject);
  45         if (ret)
  46                 return ret;
  47 
  48         return action->device->ops.destroy_flow_action(action);
  49 }
  50 
  51 static u64 esp_flags_uverbs_to_verbs(struct uverbs_attr_bundle *attrs,
  52                                      u32 flags, bool is_modify)
  53 {
  54         u64 verbs_flags = flags;
  55 
  56         if (uverbs_attr_is_valid(attrs, UVERBS_ATTR_FLOW_ACTION_ESP_ESN))
  57                 verbs_flags |= IB_FLOW_ACTION_ESP_FLAGS_ESN_TRIGGERED;
  58 
  59         if (is_modify && uverbs_attr_is_valid(attrs,
  60                                               UVERBS_ATTR_FLOW_ACTION_ESP_ATTRS))
  61                 verbs_flags |= IB_FLOW_ACTION_ESP_FLAGS_MOD_ESP_ATTRS;
  62 
  63         return verbs_flags;
  64 };
  65 
  66 static int validate_flow_action_esp_keymat_aes_gcm(struct ib_flow_action_attrs_esp_keymats *keymat)
  67 {
  68         struct ib_uverbs_flow_action_esp_keymat_aes_gcm *aes_gcm =
  69                 &keymat->keymat.aes_gcm;
  70 
  71         if (aes_gcm->iv_algo > IB_UVERBS_FLOW_ACTION_IV_ALGO_SEQ)
  72                 return -EOPNOTSUPP;
  73 
  74         if (aes_gcm->key_len != 32 &&
  75             aes_gcm->key_len != 24 &&
  76             aes_gcm->key_len != 16)
  77                 return -EINVAL;
  78 
  79         if (aes_gcm->icv_len != 16 &&
  80             aes_gcm->icv_len != 8 &&
  81             aes_gcm->icv_len != 12)
  82                 return -EINVAL;
  83 
  84         return 0;
  85 }
  86 
  87 static int (* const flow_action_esp_keymat_validate[])(struct ib_flow_action_attrs_esp_keymats *keymat) = {
  88         [IB_UVERBS_FLOW_ACTION_ESP_KEYMAT_AES_GCM] = validate_flow_action_esp_keymat_aes_gcm,
  89 };
  90 
  91 static int flow_action_esp_replay_none(struct ib_flow_action_attrs_esp_replays *replay,
  92                                        bool is_modify)
  93 {
  94         /* This is used in order to modify an esp flow action with an enabled
  95          * replay protection to a disabled one. This is only supported via
  96          * modify, as in create verb we can simply drop the REPLAY attribute and
  97          * achieve the same thing.
  98          */
  99         return is_modify ? 0 : -EINVAL;
 100 }
 101 
 102 static int flow_action_esp_replay_def_ok(struct ib_flow_action_attrs_esp_replays *replay,
 103                                          bool is_modify)
 104 {
 105         /* Some replay protections could always be enabled without validating
 106          * anything.
 107          */
 108         return 0;
 109 }
 110 
 111 static int (* const flow_action_esp_replay_validate[])(struct ib_flow_action_attrs_esp_replays *replay,
 112                                                        bool is_modify) = {
 113         [IB_UVERBS_FLOW_ACTION_ESP_REPLAY_NONE] = flow_action_esp_replay_none,
 114         [IB_UVERBS_FLOW_ACTION_ESP_REPLAY_BMP] = flow_action_esp_replay_def_ok,
 115 };
 116 
 117 static int parse_esp_ip(enum ib_flow_spec_type proto,
 118                         const void __user *val_ptr,
 119                         size_t len, union ib_flow_spec *out)
 120 {
 121         int ret;
 122         const struct ib_uverbs_flow_ipv4_filter ipv4 = {
 123                 .src_ip = cpu_to_be32(0xffffffffUL),
 124                 .dst_ip = cpu_to_be32(0xffffffffUL),
 125                 .proto = 0xff,
 126                 .tos = 0xff,
 127                 .ttl = 0xff,
 128                 .flags = 0xff,
 129         };
 130         const struct ib_uverbs_flow_ipv6_filter ipv6 = {
 131                 .src_ip = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
 132                            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
 133                 .dst_ip = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
 134                            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
 135                 .flow_label = cpu_to_be32(0xffffffffUL),
 136                 .next_hdr = 0xff,
 137                 .traffic_class = 0xff,
 138                 .hop_limit = 0xff,
 139         };
 140         union {
 141                 struct ib_uverbs_flow_ipv4_filter ipv4;
 142                 struct ib_uverbs_flow_ipv6_filter ipv6;
 143         } user_val = {};
 144         const void *user_pmask;
 145         size_t val_len;
 146 
 147         /* If the flow IPv4/IPv6 flow specifications are extended, the mask
 148          * should be changed as well.
 149          */
 150         BUILD_BUG_ON(offsetof(struct ib_uverbs_flow_ipv4_filter, flags) +
 151                      sizeof(ipv4.flags) != sizeof(ipv4));
 152         BUILD_BUG_ON(offsetof(struct ib_uverbs_flow_ipv6_filter, reserved) +
 153                      sizeof(ipv6.reserved) != sizeof(ipv6));
 154 
 155         switch (proto) {
 156         case IB_FLOW_SPEC_IPV4:
 157                 if (len > sizeof(user_val.ipv4) &&
 158                     !ib_is_buffer_cleared(val_ptr + sizeof(user_val.ipv4),
 159                                           len - sizeof(user_val.ipv4)))
 160                         return -EOPNOTSUPP;
 161 
 162                 val_len = min_t(size_t, len, sizeof(user_val.ipv4));
 163                 ret = copy_from_user(&user_val.ipv4, val_ptr,
 164                                      val_len);
 165                 if (ret)
 166                         return -EFAULT;
 167 
 168                 user_pmask = &ipv4;
 169                 break;
 170         case IB_FLOW_SPEC_IPV6:
 171                 if (len > sizeof(user_val.ipv6) &&
 172                     !ib_is_buffer_cleared(val_ptr + sizeof(user_val.ipv6),
 173                                           len - sizeof(user_val.ipv6)))
 174                         return -EOPNOTSUPP;
 175 
 176                 val_len = min_t(size_t, len, sizeof(user_val.ipv6));
 177                 ret = copy_from_user(&user_val.ipv6, val_ptr,
 178                                      val_len);
 179                 if (ret)
 180                         return -EFAULT;
 181 
 182                 user_pmask = &ipv6;
 183                 break;
 184         default:
 185                 return -EOPNOTSUPP;
 186         }
 187 
 188         return ib_uverbs_kern_spec_to_ib_spec_filter(proto, user_pmask,
 189                                                      &user_val,
 190                                                      val_len, out);
 191 }
 192 
 193 static int flow_action_esp_get_encap(struct ib_flow_spec_list *out,
 194                                      struct uverbs_attr_bundle *attrs)
 195 {
 196         struct ib_uverbs_flow_action_esp_encap uverbs_encap;
 197         int ret;
 198 
 199         ret = uverbs_copy_from(&uverbs_encap, attrs,
 200                                UVERBS_ATTR_FLOW_ACTION_ESP_ENCAP);
 201         if (ret)
 202                 return ret;
 203 
 204         /* We currently support only one encap */
 205         if (uverbs_encap.next_ptr)
 206                 return -EOPNOTSUPP;
 207 
 208         if (uverbs_encap.type != IB_FLOW_SPEC_IPV4 &&
 209             uverbs_encap.type != IB_FLOW_SPEC_IPV6)
 210                 return -EOPNOTSUPP;
 211 
 212         return parse_esp_ip(uverbs_encap.type,
 213                             u64_to_user_ptr(uverbs_encap.val_ptr),
 214                             uverbs_encap.len,
 215                             &out->spec);
 216 }
 217 
 218 struct ib_flow_action_esp_attr {
 219         struct  ib_flow_action_attrs_esp                hdr;
 220         struct  ib_flow_action_attrs_esp_keymats        keymat;
 221         struct  ib_flow_action_attrs_esp_replays        replay;
 222         /* We currently support only one spec */
 223         struct  ib_flow_spec_list                       encap;
 224 };
 225 
 226 #define ESP_LAST_SUPPORTED_FLAG         IB_UVERBS_FLOW_ACTION_ESP_FLAGS_ESN_NEW_WINDOW
 227 static int parse_flow_action_esp(struct ib_device *ib_dev,
 228                                  struct uverbs_attr_bundle *attrs,
 229                                  struct ib_flow_action_esp_attr *esp_attr,
 230                                  bool is_modify)
 231 {
 232         struct ib_uverbs_flow_action_esp uverbs_esp = {};
 233         int ret;
 234 
 235         /* Optional param, if it doesn't exist, we get -ENOENT and skip it */
 236         ret = uverbs_copy_from(&esp_attr->hdr.esn, attrs,
 237                                UVERBS_ATTR_FLOW_ACTION_ESP_ESN);
 238         if (IS_UVERBS_COPY_ERR(ret))
 239                 return ret;
 240 
 241         /* This can be called from FLOW_ACTION_ESP_MODIFY where
 242          * UVERBS_ATTR_FLOW_ACTION_ESP_ATTRS is optional
 243          */
 244         if (uverbs_attr_is_valid(attrs, UVERBS_ATTR_FLOW_ACTION_ESP_ATTRS)) {
 245                 ret = uverbs_copy_from_or_zero(&uverbs_esp, attrs,
 246                                                UVERBS_ATTR_FLOW_ACTION_ESP_ATTRS);
 247                 if (ret)
 248                         return ret;
 249 
 250                 if (uverbs_esp.flags & ~((ESP_LAST_SUPPORTED_FLAG << 1) - 1))
 251                         return -EOPNOTSUPP;
 252 
 253                 esp_attr->hdr.spi = uverbs_esp.spi;
 254                 esp_attr->hdr.seq = uverbs_esp.seq;
 255                 esp_attr->hdr.tfc_pad = uverbs_esp.tfc_pad;
 256                 esp_attr->hdr.hard_limit_pkts = uverbs_esp.hard_limit_pkts;
 257         }
 258         esp_attr->hdr.flags = esp_flags_uverbs_to_verbs(attrs, uverbs_esp.flags,
 259                                                         is_modify);
 260 
 261         if (uverbs_attr_is_valid(attrs, UVERBS_ATTR_FLOW_ACTION_ESP_KEYMAT)) {
 262                 esp_attr->keymat.protocol =
 263                         uverbs_attr_get_enum_id(attrs,
 264                                                 UVERBS_ATTR_FLOW_ACTION_ESP_KEYMAT);
 265                 ret = uverbs_copy_from_or_zero(&esp_attr->keymat.keymat,
 266                                                attrs,
 267                                                UVERBS_ATTR_FLOW_ACTION_ESP_KEYMAT);
 268                 if (ret)
 269                         return ret;
 270 
 271                 ret = flow_action_esp_keymat_validate[esp_attr->keymat.protocol](&esp_attr->keymat);
 272                 if (ret)
 273                         return ret;
 274 
 275                 esp_attr->hdr.keymat = &esp_attr->keymat;
 276         }
 277 
 278         if (uverbs_attr_is_valid(attrs, UVERBS_ATTR_FLOW_ACTION_ESP_REPLAY)) {
 279                 esp_attr->replay.protocol =
 280                         uverbs_attr_get_enum_id(attrs,
 281                                                 UVERBS_ATTR_FLOW_ACTION_ESP_REPLAY);
 282 
 283                 ret = uverbs_copy_from_or_zero(&esp_attr->replay.replay,
 284                                                attrs,
 285                                                UVERBS_ATTR_FLOW_ACTION_ESP_REPLAY);
 286                 if (ret)
 287                         return ret;
 288 
 289                 ret = flow_action_esp_replay_validate[esp_attr->replay.protocol](&esp_attr->replay,
 290                                                                                  is_modify);
 291                 if (ret)
 292                         return ret;
 293 
 294                 esp_attr->hdr.replay = &esp_attr->replay;
 295         }
 296 
 297         if (uverbs_attr_is_valid(attrs, UVERBS_ATTR_FLOW_ACTION_ESP_ENCAP)) {
 298                 ret = flow_action_esp_get_encap(&esp_attr->encap, attrs);
 299                 if (ret)
 300                         return ret;
 301 
 302                 esp_attr->hdr.encap = &esp_attr->encap;
 303         }
 304 
 305         return 0;
 306 }
 307 
 308 static int UVERBS_HANDLER(UVERBS_METHOD_FLOW_ACTION_ESP_CREATE)(
 309         struct uverbs_attr_bundle *attrs)
 310 {
 311         struct ib_uobject *uobj = uverbs_attr_get_uobject(
 312                 attrs, UVERBS_ATTR_CREATE_FLOW_ACTION_ESP_HANDLE);
 313         struct ib_device *ib_dev = attrs->context->device;
 314         int                               ret;
 315         struct ib_flow_action             *action;
 316         struct ib_flow_action_esp_attr    esp_attr = {};
 317 
 318         if (!ib_dev->ops.create_flow_action_esp)
 319                 return -EOPNOTSUPP;
 320 
 321         ret = parse_flow_action_esp(ib_dev, attrs, &esp_attr, false);
 322         if (ret)
 323                 return ret;
 324 
 325         /* No need to check as this attribute is marked as MANDATORY */
 326         action = ib_dev->ops.create_flow_action_esp(ib_dev, &esp_attr.hdr,
 327                                                     attrs);
 328         if (IS_ERR(action))
 329                 return PTR_ERR(action);
 330 
 331         uverbs_flow_action_fill_action(action, uobj, ib_dev,
 332                                        IB_FLOW_ACTION_ESP);
 333 
 334         return 0;
 335 }
 336 
 337 static int UVERBS_HANDLER(UVERBS_METHOD_FLOW_ACTION_ESP_MODIFY)(
 338         struct uverbs_attr_bundle *attrs)
 339 {
 340         struct ib_uobject *uobj = uverbs_attr_get_uobject(
 341                 attrs, UVERBS_ATTR_MODIFY_FLOW_ACTION_ESP_HANDLE);
 342         struct ib_flow_action *action = uobj->object;
 343         int                               ret;
 344         struct ib_flow_action_esp_attr    esp_attr = {};
 345 
 346         if (!action->device->ops.modify_flow_action_esp)
 347                 return -EOPNOTSUPP;
 348 
 349         ret = parse_flow_action_esp(action->device, attrs, &esp_attr, true);
 350         if (ret)
 351                 return ret;
 352 
 353         if (action->type != IB_FLOW_ACTION_ESP)
 354                 return -EINVAL;
 355 
 356         return action->device->ops.modify_flow_action_esp(action,
 357                                                           &esp_attr.hdr,
 358                                                           attrs);
 359 }
 360 
 361 static const struct uverbs_attr_spec uverbs_flow_action_esp_keymat[] = {
 362         [IB_UVERBS_FLOW_ACTION_ESP_KEYMAT_AES_GCM] = {
 363                 .type = UVERBS_ATTR_TYPE_PTR_IN,
 364                 UVERBS_ATTR_STRUCT(
 365                         struct ib_uverbs_flow_action_esp_keymat_aes_gcm,
 366                         aes_key),
 367         },
 368 };
 369 
 370 static const struct uverbs_attr_spec uverbs_flow_action_esp_replay[] = {
 371         [IB_UVERBS_FLOW_ACTION_ESP_REPLAY_NONE] = {
 372                 .type = UVERBS_ATTR_TYPE_PTR_IN,
 373                 UVERBS_ATTR_NO_DATA(),
 374         },
 375         [IB_UVERBS_FLOW_ACTION_ESP_REPLAY_BMP] = {
 376                 .type = UVERBS_ATTR_TYPE_PTR_IN,
 377                 UVERBS_ATTR_STRUCT(struct ib_uverbs_flow_action_esp_replay_bmp,
 378                                    size),
 379         },
 380 };
 381 
 382 DECLARE_UVERBS_NAMED_METHOD(
 383         UVERBS_METHOD_FLOW_ACTION_ESP_CREATE,
 384         UVERBS_ATTR_IDR(UVERBS_ATTR_CREATE_FLOW_ACTION_ESP_HANDLE,
 385                         UVERBS_OBJECT_FLOW_ACTION,
 386                         UVERBS_ACCESS_NEW,
 387                         UA_MANDATORY),
 388         UVERBS_ATTR_PTR_IN(UVERBS_ATTR_FLOW_ACTION_ESP_ATTRS,
 389                            UVERBS_ATTR_STRUCT(struct ib_uverbs_flow_action_esp,
 390                                               hard_limit_pkts),
 391                            UA_MANDATORY),
 392         UVERBS_ATTR_PTR_IN(UVERBS_ATTR_FLOW_ACTION_ESP_ESN,
 393                            UVERBS_ATTR_TYPE(__u32),
 394                            UA_OPTIONAL),
 395         UVERBS_ATTR_ENUM_IN(UVERBS_ATTR_FLOW_ACTION_ESP_KEYMAT,
 396                             uverbs_flow_action_esp_keymat,
 397                             UA_MANDATORY),
 398         UVERBS_ATTR_ENUM_IN(UVERBS_ATTR_FLOW_ACTION_ESP_REPLAY,
 399                             uverbs_flow_action_esp_replay,
 400                             UA_OPTIONAL),
 401         UVERBS_ATTR_PTR_IN(
 402                 UVERBS_ATTR_FLOW_ACTION_ESP_ENCAP,
 403                 UVERBS_ATTR_TYPE(struct ib_uverbs_flow_action_esp_encap),
 404                 UA_OPTIONAL));
 405 
 406 DECLARE_UVERBS_NAMED_METHOD(
 407         UVERBS_METHOD_FLOW_ACTION_ESP_MODIFY,
 408         UVERBS_ATTR_IDR(UVERBS_ATTR_MODIFY_FLOW_ACTION_ESP_HANDLE,
 409                         UVERBS_OBJECT_FLOW_ACTION,
 410                         UVERBS_ACCESS_WRITE,
 411                         UA_MANDATORY),
 412         UVERBS_ATTR_PTR_IN(UVERBS_ATTR_FLOW_ACTION_ESP_ATTRS,
 413                            UVERBS_ATTR_STRUCT(struct ib_uverbs_flow_action_esp,
 414                                               hard_limit_pkts),
 415                            UA_OPTIONAL),
 416         UVERBS_ATTR_PTR_IN(UVERBS_ATTR_FLOW_ACTION_ESP_ESN,
 417                            UVERBS_ATTR_TYPE(__u32),
 418                            UA_OPTIONAL),
 419         UVERBS_ATTR_ENUM_IN(UVERBS_ATTR_FLOW_ACTION_ESP_KEYMAT,
 420                             uverbs_flow_action_esp_keymat,
 421                             UA_OPTIONAL),
 422         UVERBS_ATTR_ENUM_IN(UVERBS_ATTR_FLOW_ACTION_ESP_REPLAY,
 423                             uverbs_flow_action_esp_replay,
 424                             UA_OPTIONAL),
 425         UVERBS_ATTR_PTR_IN(
 426                 UVERBS_ATTR_FLOW_ACTION_ESP_ENCAP,
 427                 UVERBS_ATTR_TYPE(struct ib_uverbs_flow_action_esp_encap),
 428                 UA_OPTIONAL));
 429 
 430 DECLARE_UVERBS_NAMED_METHOD_DESTROY(
 431         UVERBS_METHOD_FLOW_ACTION_DESTROY,
 432         UVERBS_ATTR_IDR(UVERBS_ATTR_DESTROY_FLOW_ACTION_HANDLE,
 433                         UVERBS_OBJECT_FLOW_ACTION,
 434                         UVERBS_ACCESS_DESTROY,
 435                         UA_MANDATORY));
 436 
 437 DECLARE_UVERBS_NAMED_OBJECT(
 438         UVERBS_OBJECT_FLOW_ACTION,
 439         UVERBS_TYPE_ALLOC_IDR(uverbs_free_flow_action),
 440         &UVERBS_METHOD(UVERBS_METHOD_FLOW_ACTION_ESP_CREATE),
 441         &UVERBS_METHOD(UVERBS_METHOD_FLOW_ACTION_DESTROY),
 442         &UVERBS_METHOD(UVERBS_METHOD_FLOW_ACTION_ESP_MODIFY));
 443 
 444 const struct uapi_definition uverbs_def_obj_flow_action[] = {
 445         UAPI_DEF_CHAIN_OBJ_TREE_NAMED(
 446                 UVERBS_OBJECT_FLOW_ACTION,
 447                 UAPI_DEF_OBJ_NEEDS_FN(destroy_flow_action)),
 448         {}
 449 };

/* [<][>][^][v][top][bottom][index][help] */