linux/net/sched/act_tunnel_key.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2016, Amir Vadai <amir@vadai.me>
   3 * Copyright (c) 2016, Mellanox Technologies. All rights reserved.
   4 *
   5 * This program is free software; you can redistribute it and/or modify
   6 * it under the terms of the GNU General Public License as published by
   7 * the Free Software Foundation; either version 2 of the License, or
   8 * (at your option) any later version.
   9 */
  10
  11#include <linux/module.h>
  12#include <linux/init.h>
  13#include <linux/kernel.h>
  14#include <linux/skbuff.h>
  15#include <linux/rtnetlink.h>
  16#include <net/geneve.h>
  17#include <net/netlink.h>
  18#include <net/pkt_sched.h>
  19#include <net/dst.h>
  20
  21#include <linux/tc_act/tc_tunnel_key.h>
  22#include <net/tc_act/tc_tunnel_key.h>
  23
  24static unsigned int tunnel_key_net_id;
  25static struct tc_action_ops act_tunnel_key_ops;
  26
  27static int tunnel_key_act(struct sk_buff *skb, const struct tc_action *a,
  28                          struct tcf_result *res)
  29{
  30        struct tcf_tunnel_key *t = to_tunnel_key(a);
  31        struct tcf_tunnel_key_params *params;
  32        int action;
  33
  34        params = rcu_dereference_bh(t->params);
  35
  36        tcf_lastuse_update(&t->tcf_tm);
  37        bstats_cpu_update(this_cpu_ptr(t->common.cpu_bstats), skb);
  38        action = READ_ONCE(t->tcf_action);
  39
  40        switch (params->tcft_action) {
  41        case TCA_TUNNEL_KEY_ACT_RELEASE:
  42                skb_dst_drop(skb);
  43                break;
  44        case TCA_TUNNEL_KEY_ACT_SET:
  45                skb_dst_drop(skb);
  46                skb_dst_set(skb, dst_clone(&params->tcft_enc_metadata->dst));
  47                break;
  48        default:
  49                WARN_ONCE(1, "Bad tunnel_key action %d.\n",
  50                          params->tcft_action);
  51                break;
  52        }
  53
  54        return action;
  55}
  56
  57static const struct nla_policy
  58enc_opts_policy[TCA_TUNNEL_KEY_ENC_OPTS_MAX + 1] = {
  59        [TCA_TUNNEL_KEY_ENC_OPTS_GENEVE]        = { .type = NLA_NESTED },
  60};
  61
  62static const struct nla_policy
  63geneve_opt_policy[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_MAX + 1] = {
  64        [TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS]      = { .type = NLA_U16 },
  65        [TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE]       = { .type = NLA_U8 },
  66        [TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA]       = { .type = NLA_BINARY,
  67                                                       .len = 128 },
  68};
  69
  70static int
  71tunnel_key_copy_geneve_opt(const struct nlattr *nla, void *dst, int dst_len,
  72                           struct netlink_ext_ack *extack)
  73{
  74        struct nlattr *tb[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_MAX + 1];
  75        int err, data_len, opt_len;
  76        u8 *data;
  77
  78        err = nla_parse_nested(tb, TCA_TUNNEL_KEY_ENC_OPT_GENEVE_MAX,
  79                               nla, geneve_opt_policy, extack);
  80        if (err < 0)
  81                return err;
  82
  83        if (!tb[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS] ||
  84            !tb[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE] ||
  85            !tb[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA]) {
  86                NL_SET_ERR_MSG(extack, "Missing tunnel key geneve option class, type or data");
  87                return -EINVAL;
  88        }
  89
  90        data = nla_data(tb[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA]);
  91        data_len = nla_len(tb[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA]);
  92        if (data_len < 4) {
  93                NL_SET_ERR_MSG(extack, "Tunnel key geneve option data is less than 4 bytes long");
  94                return -ERANGE;
  95        }
  96        if (data_len % 4) {
  97                NL_SET_ERR_MSG(extack, "Tunnel key geneve option data is not a multiple of 4 bytes long");
  98                return -ERANGE;
  99        }
 100
 101        opt_len = sizeof(struct geneve_opt) + data_len;
 102        if (dst) {
 103                struct geneve_opt *opt = dst;
 104
 105                WARN_ON(dst_len < opt_len);
 106
 107                opt->opt_class =
 108                        nla_get_be16(tb[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS]);
 109                opt->type = nla_get_u8(tb[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE]);
 110                opt->length = data_len / 4; /* length is in units of 4 bytes */
 111                opt->r1 = 0;
 112                opt->r2 = 0;
 113                opt->r3 = 0;
 114
 115                memcpy(opt + 1, data, data_len);
 116        }
 117
 118        return opt_len;
 119}
 120
 121static int tunnel_key_copy_opts(const struct nlattr *nla, u8 *dst,
 122                                int dst_len, struct netlink_ext_ack *extack)
 123{
 124        int err, rem, opt_len, len = nla_len(nla), opts_len = 0;
 125        const struct nlattr *attr, *head = nla_data(nla);
 126
 127        err = nla_validate(head, len, TCA_TUNNEL_KEY_ENC_OPTS_MAX,
 128                           enc_opts_policy, extack);
 129        if (err)
 130                return err;
 131
 132        nla_for_each_attr(attr, head, len, rem) {
 133                switch (nla_type(attr)) {
 134                case TCA_TUNNEL_KEY_ENC_OPTS_GENEVE:
 135                        opt_len = tunnel_key_copy_geneve_opt(attr, dst,
 136                                                             dst_len, extack);
 137                        if (opt_len < 0)
 138                                return opt_len;
 139                        opts_len += opt_len;
 140                        if (dst) {
 141                                dst_len -= opt_len;
 142                                dst += opt_len;
 143                        }
 144                        break;
 145                }
 146        }
 147
 148        if (!opts_len) {
 149                NL_SET_ERR_MSG(extack, "Empty list of tunnel options");
 150                return -EINVAL;
 151        }
 152
 153        if (rem > 0) {
 154                NL_SET_ERR_MSG(extack, "Trailing data after parsing tunnel key options attributes");
 155                return -EINVAL;
 156        }
 157
 158        return opts_len;
 159}
 160
 161static int tunnel_key_get_opts_len(struct nlattr *nla,
 162                                   struct netlink_ext_ack *extack)
 163{
 164        return tunnel_key_copy_opts(nla, NULL, 0, extack);
 165}
 166
 167static int tunnel_key_opts_set(struct nlattr *nla, struct ip_tunnel_info *info,
 168                               int opts_len, struct netlink_ext_ack *extack)
 169{
 170        info->options_len = opts_len;
 171        switch (nla_type(nla_data(nla))) {
 172        case TCA_TUNNEL_KEY_ENC_OPTS_GENEVE:
 173#if IS_ENABLED(CONFIG_INET)
 174                info->key.tun_flags |= TUNNEL_GENEVE_OPT;
 175                return tunnel_key_copy_opts(nla, ip_tunnel_info_opts(info),
 176                                            opts_len, extack);
 177#else
 178                return -EAFNOSUPPORT;
 179#endif
 180        default:
 181                NL_SET_ERR_MSG(extack, "Cannot set tunnel options for unknown tunnel type");
 182                return -EINVAL;
 183        }
 184}
 185
 186static const struct nla_policy tunnel_key_policy[TCA_TUNNEL_KEY_MAX + 1] = {
 187        [TCA_TUNNEL_KEY_PARMS]      = { .len = sizeof(struct tc_tunnel_key) },
 188        [TCA_TUNNEL_KEY_ENC_IPV4_SRC] = { .type = NLA_U32 },
 189        [TCA_TUNNEL_KEY_ENC_IPV4_DST] = { .type = NLA_U32 },
 190        [TCA_TUNNEL_KEY_ENC_IPV6_SRC] = { .len = sizeof(struct in6_addr) },
 191        [TCA_TUNNEL_KEY_ENC_IPV6_DST] = { .len = sizeof(struct in6_addr) },
 192        [TCA_TUNNEL_KEY_ENC_KEY_ID]   = { .type = NLA_U32 },
 193        [TCA_TUNNEL_KEY_ENC_DST_PORT] = {.type = NLA_U16},
 194        [TCA_TUNNEL_KEY_NO_CSUM]      = { .type = NLA_U8 },
 195        [TCA_TUNNEL_KEY_ENC_OPTS]     = { .type = NLA_NESTED },
 196        [TCA_TUNNEL_KEY_ENC_TOS]      = { .type = NLA_U8 },
 197        [TCA_TUNNEL_KEY_ENC_TTL]      = { .type = NLA_U8 },
 198};
 199
 200static int tunnel_key_init(struct net *net, struct nlattr *nla,
 201                           struct nlattr *est, struct tc_action **a,
 202                           int ovr, int bind, bool rtnl_held,
 203                           struct netlink_ext_ack *extack)
 204{
 205        struct tc_action_net *tn = net_generic(net, tunnel_key_net_id);
 206        struct nlattr *tb[TCA_TUNNEL_KEY_MAX + 1];
 207        struct tcf_tunnel_key_params *params_new;
 208        struct metadata_dst *metadata = NULL;
 209        struct tc_tunnel_key *parm;
 210        struct tcf_tunnel_key *t;
 211        bool exists = false;
 212        __be16 dst_port = 0;
 213        int opts_len = 0;
 214        __be64 key_id;
 215        __be16 flags;
 216        u8 tos, ttl;
 217        int ret = 0;
 218        int err;
 219
 220        if (!nla) {
 221                NL_SET_ERR_MSG(extack, "Tunnel requires attributes to be passed");
 222                return -EINVAL;
 223        }
 224
 225        err = nla_parse_nested(tb, TCA_TUNNEL_KEY_MAX, nla, tunnel_key_policy,
 226                               extack);
 227        if (err < 0) {
 228                NL_SET_ERR_MSG(extack, "Failed to parse nested tunnel key attributes");
 229                return err;
 230        }
 231
 232        if (!tb[TCA_TUNNEL_KEY_PARMS]) {
 233                NL_SET_ERR_MSG(extack, "Missing tunnel key parameters");
 234                return -EINVAL;
 235        }
 236
 237        parm = nla_data(tb[TCA_TUNNEL_KEY_PARMS]);
 238        err = tcf_idr_check_alloc(tn, &parm->index, a, bind);
 239        if (err < 0)
 240                return err;
 241        exists = err;
 242        if (exists && bind)
 243                return 0;
 244
 245        switch (parm->t_action) {
 246        case TCA_TUNNEL_KEY_ACT_RELEASE:
 247                break;
 248        case TCA_TUNNEL_KEY_ACT_SET:
 249                if (!tb[TCA_TUNNEL_KEY_ENC_KEY_ID]) {
 250                        NL_SET_ERR_MSG(extack, "Missing tunnel key id");
 251                        ret = -EINVAL;
 252                        goto err_out;
 253                }
 254
 255                key_id = key32_to_tunnel_id(nla_get_be32(tb[TCA_TUNNEL_KEY_ENC_KEY_ID]));
 256
 257                flags = TUNNEL_KEY | TUNNEL_CSUM;
 258                if (tb[TCA_TUNNEL_KEY_NO_CSUM] &&
 259                    nla_get_u8(tb[TCA_TUNNEL_KEY_NO_CSUM]))
 260                        flags &= ~TUNNEL_CSUM;
 261
 262                if (tb[TCA_TUNNEL_KEY_ENC_DST_PORT])
 263                        dst_port = nla_get_be16(tb[TCA_TUNNEL_KEY_ENC_DST_PORT]);
 264
 265                if (tb[TCA_TUNNEL_KEY_ENC_OPTS]) {
 266                        opts_len = tunnel_key_get_opts_len(tb[TCA_TUNNEL_KEY_ENC_OPTS],
 267                                                           extack);
 268                        if (opts_len < 0) {
 269                                ret = opts_len;
 270                                goto err_out;
 271                        }
 272                }
 273
 274                tos = 0;
 275                if (tb[TCA_TUNNEL_KEY_ENC_TOS])
 276                        tos = nla_get_u8(tb[TCA_TUNNEL_KEY_ENC_TOS]);
 277                ttl = 0;
 278                if (tb[TCA_TUNNEL_KEY_ENC_TTL])
 279                        ttl = nla_get_u8(tb[TCA_TUNNEL_KEY_ENC_TTL]);
 280
 281                if (tb[TCA_TUNNEL_KEY_ENC_IPV4_SRC] &&
 282                    tb[TCA_TUNNEL_KEY_ENC_IPV4_DST]) {
 283                        __be32 saddr;
 284                        __be32 daddr;
 285
 286                        saddr = nla_get_in_addr(tb[TCA_TUNNEL_KEY_ENC_IPV4_SRC]);
 287                        daddr = nla_get_in_addr(tb[TCA_TUNNEL_KEY_ENC_IPV4_DST]);
 288
 289                        metadata = __ip_tun_set_dst(saddr, daddr, tos, ttl,
 290                                                    dst_port, flags,
 291                                                    key_id, opts_len);
 292                } else if (tb[TCA_TUNNEL_KEY_ENC_IPV6_SRC] &&
 293                           tb[TCA_TUNNEL_KEY_ENC_IPV6_DST]) {
 294                        struct in6_addr saddr;
 295                        struct in6_addr daddr;
 296
 297                        saddr = nla_get_in6_addr(tb[TCA_TUNNEL_KEY_ENC_IPV6_SRC]);
 298                        daddr = nla_get_in6_addr(tb[TCA_TUNNEL_KEY_ENC_IPV6_DST]);
 299
 300                        metadata = __ipv6_tun_set_dst(&saddr, &daddr, tos, ttl, dst_port,
 301                                                      0, flags,
 302                                                      key_id, 0);
 303                } else {
 304                        NL_SET_ERR_MSG(extack, "Missing either ipv4 or ipv6 src and dst");
 305                        ret = -EINVAL;
 306                        goto err_out;
 307                }
 308
 309                if (!metadata) {
 310                        NL_SET_ERR_MSG(extack, "Cannot allocate tunnel metadata dst");
 311                        ret = -ENOMEM;
 312                        goto err_out;
 313                }
 314
 315                if (opts_len) {
 316                        ret = tunnel_key_opts_set(tb[TCA_TUNNEL_KEY_ENC_OPTS],
 317                                                  &metadata->u.tun_info,
 318                                                  opts_len, extack);
 319                        if (ret < 0)
 320                                goto release_tun_meta;
 321                }
 322
 323                metadata->u.tun_info.mode |= IP_TUNNEL_INFO_TX;
 324                break;
 325        default:
 326                NL_SET_ERR_MSG(extack, "Unknown tunnel key action");
 327                ret = -EINVAL;
 328                goto err_out;
 329        }
 330
 331        if (!exists) {
 332                ret = tcf_idr_create(tn, parm->index, est, a,
 333                                     &act_tunnel_key_ops, bind, true);
 334                if (ret) {
 335                        NL_SET_ERR_MSG(extack, "Cannot create TC IDR");
 336                        goto release_tun_meta;
 337                }
 338
 339                ret = ACT_P_CREATED;
 340        } else if (!ovr) {
 341                NL_SET_ERR_MSG(extack, "TC IDR already exists");
 342                ret = -EEXIST;
 343                goto release_tun_meta;
 344        }
 345
 346        t = to_tunnel_key(*a);
 347
 348        params_new = kzalloc(sizeof(*params_new), GFP_KERNEL);
 349        if (unlikely(!params_new)) {
 350                NL_SET_ERR_MSG(extack, "Cannot allocate tunnel key parameters");
 351                ret = -ENOMEM;
 352                exists = true;
 353                goto release_tun_meta;
 354        }
 355        params_new->tcft_action = parm->t_action;
 356        params_new->tcft_enc_metadata = metadata;
 357
 358        spin_lock_bh(&t->tcf_lock);
 359        t->tcf_action = parm->action;
 360        rcu_swap_protected(t->params, params_new,
 361                           lockdep_is_held(&t->tcf_lock));
 362        spin_unlock_bh(&t->tcf_lock);
 363        if (params_new)
 364                kfree_rcu(params_new, rcu);
 365
 366        if (ret == ACT_P_CREATED)
 367                tcf_idr_insert(tn, *a);
 368
 369        return ret;
 370
 371release_tun_meta:
 372        dst_release(&metadata->dst);
 373
 374err_out:
 375        if (exists)
 376                tcf_idr_release(*a, bind);
 377        else
 378                tcf_idr_cleanup(tn, parm->index);
 379        return ret;
 380}
 381
 382static void tunnel_key_release(struct tc_action *a)
 383{
 384        struct tcf_tunnel_key *t = to_tunnel_key(a);
 385        struct tcf_tunnel_key_params *params;
 386
 387        params = rcu_dereference_protected(t->params, 1);
 388        if (params) {
 389                if (params->tcft_action == TCA_TUNNEL_KEY_ACT_SET)
 390                        dst_release(&params->tcft_enc_metadata->dst);
 391
 392                kfree_rcu(params, rcu);
 393        }
 394}
 395
 396static int tunnel_key_geneve_opts_dump(struct sk_buff *skb,
 397                                       const struct ip_tunnel_info *info)
 398{
 399        int len = info->options_len;
 400        u8 *src = (u8 *)(info + 1);
 401        struct nlattr *start;
 402
 403        start = nla_nest_start(skb, TCA_TUNNEL_KEY_ENC_OPTS_GENEVE);
 404        if (!start)
 405                return -EMSGSIZE;
 406
 407        while (len > 0) {
 408                struct geneve_opt *opt = (struct geneve_opt *)src;
 409
 410                if (nla_put_be16(skb, TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS,
 411                                 opt->opt_class) ||
 412                    nla_put_u8(skb, TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE,
 413                               opt->type) ||
 414                    nla_put(skb, TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA,
 415                            opt->length * 4, opt + 1)) {
 416                        nla_nest_cancel(skb, start);
 417                        return -EMSGSIZE;
 418                }
 419
 420                len -= sizeof(struct geneve_opt) + opt->length * 4;
 421                src += sizeof(struct geneve_opt) + opt->length * 4;
 422        }
 423
 424        nla_nest_end(skb, start);
 425        return 0;
 426}
 427
 428static int tunnel_key_opts_dump(struct sk_buff *skb,
 429                                const struct ip_tunnel_info *info)
 430{
 431        struct nlattr *start;
 432        int err = -EINVAL;
 433
 434        if (!info->options_len)
 435                return 0;
 436
 437        start = nla_nest_start(skb, TCA_TUNNEL_KEY_ENC_OPTS);
 438        if (!start)
 439                return -EMSGSIZE;
 440
 441        if (info->key.tun_flags & TUNNEL_GENEVE_OPT) {
 442                err = tunnel_key_geneve_opts_dump(skb, info);
 443                if (err)
 444                        goto err_out;
 445        } else {
 446err_out:
 447                nla_nest_cancel(skb, start);
 448                return err;
 449        }
 450
 451        nla_nest_end(skb, start);
 452        return 0;
 453}
 454
 455static int tunnel_key_dump_addresses(struct sk_buff *skb,
 456                                     const struct ip_tunnel_info *info)
 457{
 458        unsigned short family = ip_tunnel_info_af(info);
 459
 460        if (family == AF_INET) {
 461                __be32 saddr = info->key.u.ipv4.src;
 462                __be32 daddr = info->key.u.ipv4.dst;
 463
 464                if (!nla_put_in_addr(skb, TCA_TUNNEL_KEY_ENC_IPV4_SRC, saddr) &&
 465                    !nla_put_in_addr(skb, TCA_TUNNEL_KEY_ENC_IPV4_DST, daddr))
 466                        return 0;
 467        }
 468
 469        if (family == AF_INET6) {
 470                const struct in6_addr *saddr6 = &info->key.u.ipv6.src;
 471                const struct in6_addr *daddr6 = &info->key.u.ipv6.dst;
 472
 473                if (!nla_put_in6_addr(skb,
 474                                      TCA_TUNNEL_KEY_ENC_IPV6_SRC, saddr6) &&
 475                    !nla_put_in6_addr(skb,
 476                                      TCA_TUNNEL_KEY_ENC_IPV6_DST, daddr6))
 477                        return 0;
 478        }
 479
 480        return -EINVAL;
 481}
 482
 483static int tunnel_key_dump(struct sk_buff *skb, struct tc_action *a,
 484                           int bind, int ref)
 485{
 486        unsigned char *b = skb_tail_pointer(skb);
 487        struct tcf_tunnel_key *t = to_tunnel_key(a);
 488        struct tcf_tunnel_key_params *params;
 489        struct tc_tunnel_key opt = {
 490                .index    = t->tcf_index,
 491                .refcnt   = refcount_read(&t->tcf_refcnt) - ref,
 492                .bindcnt  = atomic_read(&t->tcf_bindcnt) - bind,
 493        };
 494        struct tcf_t tm;
 495
 496        spin_lock_bh(&t->tcf_lock);
 497        params = rcu_dereference_protected(t->params,
 498                                           lockdep_is_held(&t->tcf_lock));
 499        opt.action   = t->tcf_action;
 500        opt.t_action = params->tcft_action;
 501
 502        if (nla_put(skb, TCA_TUNNEL_KEY_PARMS, sizeof(opt), &opt))
 503                goto nla_put_failure;
 504
 505        if (params->tcft_action == TCA_TUNNEL_KEY_ACT_SET) {
 506                struct ip_tunnel_info *info =
 507                        &params->tcft_enc_metadata->u.tun_info;
 508                struct ip_tunnel_key *key = &info->key;
 509                __be32 key_id = tunnel_id_to_key32(key->tun_id);
 510
 511                if (nla_put_be32(skb, TCA_TUNNEL_KEY_ENC_KEY_ID, key_id) ||
 512                    tunnel_key_dump_addresses(skb,
 513                                              &params->tcft_enc_metadata->u.tun_info) ||
 514                    nla_put_be16(skb, TCA_TUNNEL_KEY_ENC_DST_PORT, key->tp_dst) ||
 515                    nla_put_u8(skb, TCA_TUNNEL_KEY_NO_CSUM,
 516                               !(key->tun_flags & TUNNEL_CSUM)) ||
 517                    tunnel_key_opts_dump(skb, info))
 518                        goto nla_put_failure;
 519
 520                if (key->tos && nla_put_u8(skb, TCA_TUNNEL_KEY_ENC_TOS, key->tos))
 521                        goto nla_put_failure;
 522
 523                if (key->ttl && nla_put_u8(skb, TCA_TUNNEL_KEY_ENC_TTL, key->ttl))
 524                        goto nla_put_failure;
 525        }
 526
 527        tcf_tm_dump(&tm, &t->tcf_tm);
 528        if (nla_put_64bit(skb, TCA_TUNNEL_KEY_TM, sizeof(tm),
 529                          &tm, TCA_TUNNEL_KEY_PAD))
 530                goto nla_put_failure;
 531        spin_unlock_bh(&t->tcf_lock);
 532
 533        return skb->len;
 534
 535nla_put_failure:
 536        spin_unlock_bh(&t->tcf_lock);
 537        nlmsg_trim(skb, b);
 538        return -1;
 539}
 540
 541static int tunnel_key_walker(struct net *net, struct sk_buff *skb,
 542                             struct netlink_callback *cb, int type,
 543                             const struct tc_action_ops *ops,
 544                             struct netlink_ext_ack *extack)
 545{
 546        struct tc_action_net *tn = net_generic(net, tunnel_key_net_id);
 547
 548        return tcf_generic_walker(tn, skb, cb, type, ops, extack);
 549}
 550
 551static int tunnel_key_search(struct net *net, struct tc_action **a, u32 index,
 552                             struct netlink_ext_ack *extack)
 553{
 554        struct tc_action_net *tn = net_generic(net, tunnel_key_net_id);
 555
 556        return tcf_idr_search(tn, a, index);
 557}
 558
 559static struct tc_action_ops act_tunnel_key_ops = {
 560        .kind           =       "tunnel_key",
 561        .type           =       TCA_ACT_TUNNEL_KEY,
 562        .owner          =       THIS_MODULE,
 563        .act            =       tunnel_key_act,
 564        .dump           =       tunnel_key_dump,
 565        .init           =       tunnel_key_init,
 566        .cleanup        =       tunnel_key_release,
 567        .walk           =       tunnel_key_walker,
 568        .lookup         =       tunnel_key_search,
 569        .size           =       sizeof(struct tcf_tunnel_key),
 570};
 571
 572static __net_init int tunnel_key_init_net(struct net *net)
 573{
 574        struct tc_action_net *tn = net_generic(net, tunnel_key_net_id);
 575
 576        return tc_action_net_init(tn, &act_tunnel_key_ops);
 577}
 578
 579static void __net_exit tunnel_key_exit_net(struct list_head *net_list)
 580{
 581        tc_action_net_exit(net_list, tunnel_key_net_id);
 582}
 583
 584static struct pernet_operations tunnel_key_net_ops = {
 585        .init = tunnel_key_init_net,
 586        .exit_batch = tunnel_key_exit_net,
 587        .id   = &tunnel_key_net_id,
 588        .size = sizeof(struct tc_action_net),
 589};
 590
 591static int __init tunnel_key_init_module(void)
 592{
 593        return tcf_register_action(&act_tunnel_key_ops, &tunnel_key_net_ops);
 594}
 595
 596static void __exit tunnel_key_cleanup_module(void)
 597{
 598        tcf_unregister_action(&act_tunnel_key_ops, &tunnel_key_net_ops);
 599}
 600
 601module_init(tunnel_key_init_module);
 602module_exit(tunnel_key_cleanup_module);
 603
 604MODULE_AUTHOR("Amir Vadai <amir@vadai.me>");
 605MODULE_DESCRIPTION("ip tunnel manipulation actions");
 606MODULE_LICENSE("GPL v2");
 607