linux/drivers/infiniband/core/uverbs_std_types_flow_action.c
<<
>>
Prefs
   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
  37static 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
  51static 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
  66static 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
  87static 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
  91static 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
 102static 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
 111static 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
 117static 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
 193static 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
 218struct 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
 227static 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
 308static 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
 337static 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
 361static 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
 370static 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
 382DECLARE_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
 406DECLARE_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
 430DECLARE_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
 437DECLARE_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
 444const 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};
 450