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 24 static unsigned int tunnel_key_net_id; 25 static struct tc_action_ops act_tunnel_key_ops; 26 27 static 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(¶ms->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 57 static const struct nla_policy 58 enc_opts_policy[TCA_TUNNEL_KEY_ENC_OPTS_MAX + 1] = { 59 [TCA_TUNNEL_KEY_ENC_OPTS_GENEVE] = { .type = NLA_NESTED }, 60 }; 61 62 static const struct nla_policy 63 geneve_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 70 static int 71 tunnel_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 121 static 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 161 static 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 167 static 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 186 static 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 200 static void tunnel_key_release_params(struct tcf_tunnel_key_params *p) 201 { 202 if (!p) 203 return; 204 if (p->tcft_action == TCA_TUNNEL_KEY_ACT_SET) { 205 #ifdef CONFIG_DST_CACHE 206 struct ip_tunnel_info *info = &p->tcft_enc_metadata->u.tun_info; 207 208 dst_cache_destroy(&info->dst_cache); 209 #endif 210 dst_release(&p->tcft_enc_metadata->dst); 211 } 212 kfree_rcu(p, rcu); 213 } 214 215 static int tunnel_key_init(struct net *net, struct nlattr *nla, 216 struct nlattr *est, struct tc_action **a, 217 int ovr, int bind, bool rtnl_held, 218 struct netlink_ext_ack *extack) 219 { 220 struct tc_action_net *tn = net_generic(net, tunnel_key_net_id); 221 struct nlattr *tb[TCA_TUNNEL_KEY_MAX + 1]; 222 struct tcf_tunnel_key_params *params_new; 223 struct metadata_dst *metadata = NULL; 224 struct tc_tunnel_key *parm; 225 struct tcf_tunnel_key *t; 226 bool exists = false; 227 __be16 dst_port = 0; 228 __be64 key_id = 0; 229 int opts_len = 0; 230 __be16 flags = 0; 231 u8 tos, ttl; 232 int ret = 0; 233 int err; 234 235 if (!nla) { 236 NL_SET_ERR_MSG(extack, "Tunnel requires attributes to be passed"); 237 return -EINVAL; 238 } 239 240 err = nla_parse_nested(tb, TCA_TUNNEL_KEY_MAX, nla, tunnel_key_policy, 241 extack); 242 if (err < 0) { 243 NL_SET_ERR_MSG(extack, "Failed to parse nested tunnel key attributes"); 244 return err; 245 } 246 247 if (!tb[TCA_TUNNEL_KEY_PARMS]) { 248 NL_SET_ERR_MSG(extack, "Missing tunnel key parameters"); 249 return -EINVAL; 250 } 251 252 parm = nla_data(tb[TCA_TUNNEL_KEY_PARMS]); 253 err = tcf_idr_check_alloc(tn, &parm->index, a, bind); 254 if (err < 0) 255 return err; 256 exists = err; 257 if (exists && bind) 258 return 0; 259 260 switch (parm->t_action) { 261 case TCA_TUNNEL_KEY_ACT_RELEASE: 262 break; 263 case TCA_TUNNEL_KEY_ACT_SET: 264 if (tb[TCA_TUNNEL_KEY_ENC_KEY_ID]) { 265 __be32 key32; 266 267 key32 = nla_get_be32(tb[TCA_TUNNEL_KEY_ENC_KEY_ID]); 268 key_id = key32_to_tunnel_id(key32); 269 flags = TUNNEL_KEY; 270 } 271 272 flags |= TUNNEL_CSUM; 273 if (tb[TCA_TUNNEL_KEY_NO_CSUM] && 274 nla_get_u8(tb[TCA_TUNNEL_KEY_NO_CSUM])) 275 flags &= ~TUNNEL_CSUM; 276 277 if (tb[TCA_TUNNEL_KEY_ENC_DST_PORT]) 278 dst_port = nla_get_be16(tb[TCA_TUNNEL_KEY_ENC_DST_PORT]); 279 280 if (tb[TCA_TUNNEL_KEY_ENC_OPTS]) { 281 opts_len = tunnel_key_get_opts_len(tb[TCA_TUNNEL_KEY_ENC_OPTS], 282 extack); 283 if (opts_len < 0) { 284 ret = opts_len; 285 goto err_out; 286 } 287 } 288 289 tos = 0; 290 if (tb[TCA_TUNNEL_KEY_ENC_TOS]) 291 tos = nla_get_u8(tb[TCA_TUNNEL_KEY_ENC_TOS]); 292 ttl = 0; 293 if (tb[TCA_TUNNEL_KEY_ENC_TTL]) 294 ttl = nla_get_u8(tb[TCA_TUNNEL_KEY_ENC_TTL]); 295 296 if (tb[TCA_TUNNEL_KEY_ENC_IPV4_SRC] && 297 tb[TCA_TUNNEL_KEY_ENC_IPV4_DST]) { 298 __be32 saddr; 299 __be32 daddr; 300 301 saddr = nla_get_in_addr(tb[TCA_TUNNEL_KEY_ENC_IPV4_SRC]); 302 daddr = nla_get_in_addr(tb[TCA_TUNNEL_KEY_ENC_IPV4_DST]); 303 304 metadata = __ip_tun_set_dst(saddr, daddr, tos, ttl, 305 dst_port, flags, 306 key_id, opts_len); 307 } else if (tb[TCA_TUNNEL_KEY_ENC_IPV6_SRC] && 308 tb[TCA_TUNNEL_KEY_ENC_IPV6_DST]) { 309 struct in6_addr saddr; 310 struct in6_addr daddr; 311 312 saddr = nla_get_in6_addr(tb[TCA_TUNNEL_KEY_ENC_IPV6_SRC]); 313 daddr = nla_get_in6_addr(tb[TCA_TUNNEL_KEY_ENC_IPV6_DST]); 314 315 metadata = __ipv6_tun_set_dst(&saddr, &daddr, tos, ttl, dst_port, 316 0, flags, 317 key_id, 0); 318 } else { 319 NL_SET_ERR_MSG(extack, "Missing either ipv4 or ipv6 src and dst"); 320 ret = -EINVAL; 321 goto err_out; 322 } 323 324 if (!metadata) { 325 NL_SET_ERR_MSG(extack, "Cannot allocate tunnel metadata dst"); 326 ret = -ENOMEM; 327 goto err_out; 328 } 329 330 #ifdef CONFIG_DST_CACHE 331 ret = dst_cache_init(&metadata->u.tun_info.dst_cache, GFP_KERNEL); 332 if (ret) 333 goto release_tun_meta; 334 #endif 335 336 if (opts_len) { 337 ret = tunnel_key_opts_set(tb[TCA_TUNNEL_KEY_ENC_OPTS], 338 &metadata->u.tun_info, 339 opts_len, extack); 340 if (ret < 0) 341 goto release_dst_cache; 342 } 343 344 metadata->u.tun_info.mode |= IP_TUNNEL_INFO_TX; 345 break; 346 default: 347 NL_SET_ERR_MSG(extack, "Unknown tunnel key action"); 348 ret = -EINVAL; 349 goto err_out; 350 } 351 352 if (!exists) { 353 ret = tcf_idr_create(tn, parm->index, est, a, 354 &act_tunnel_key_ops, bind, true); 355 if (ret) { 356 NL_SET_ERR_MSG(extack, "Cannot create TC IDR"); 357 goto release_dst_cache; 358 } 359 360 ret = ACT_P_CREATED; 361 } else if (!ovr) { 362 NL_SET_ERR_MSG(extack, "TC IDR already exists"); 363 ret = -EEXIST; 364 goto release_dst_cache; 365 } 366 367 t = to_tunnel_key(*a); 368 369 params_new = kzalloc(sizeof(*params_new), GFP_KERNEL); 370 if (unlikely(!params_new)) { 371 NL_SET_ERR_MSG(extack, "Cannot allocate tunnel key parameters"); 372 ret = -ENOMEM; 373 exists = true; 374 goto release_dst_cache; 375 } 376 params_new->tcft_action = parm->t_action; 377 params_new->tcft_enc_metadata = metadata; 378 379 spin_lock_bh(&t->tcf_lock); 380 t->tcf_action = parm->action; 381 rcu_swap_protected(t->params, params_new, 382 lockdep_is_held(&t->tcf_lock)); 383 spin_unlock_bh(&t->tcf_lock); 384 tunnel_key_release_params(params_new); 385 386 if (ret == ACT_P_CREATED) 387 tcf_idr_insert(tn, *a); 388 389 return ret; 390 391 release_dst_cache: 392 #ifdef CONFIG_DST_CACHE 393 if (metadata) 394 dst_cache_destroy(&metadata->u.tun_info.dst_cache); 395 release_tun_meta: 396 #endif 397 if (metadata) 398 dst_release(&metadata->dst); 399 400 err_out: 401 if (exists) 402 tcf_idr_release(*a, bind); 403 else 404 tcf_idr_cleanup(tn, parm->index); 405 return ret; 406 } 407 408 static void tunnel_key_release(struct tc_action *a) 409 { 410 struct tcf_tunnel_key *t = to_tunnel_key(a); 411 struct tcf_tunnel_key_params *params; 412 413 params = rcu_dereference_protected(t->params, 1); 414 tunnel_key_release_params(params); 415 } 416 417 static int tunnel_key_geneve_opts_dump(struct sk_buff *skb, 418 const struct ip_tunnel_info *info) 419 { 420 int len = info->options_len; 421 u8 *src = (u8 *)(info + 1); 422 struct nlattr *start; 423 424 start = nla_nest_start(skb, TCA_TUNNEL_KEY_ENC_OPTS_GENEVE); 425 if (!start) 426 return -EMSGSIZE; 427 428 while (len > 0) { 429 struct geneve_opt *opt = (struct geneve_opt *)src; 430 431 if (nla_put_be16(skb, TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS, 432 opt->opt_class) || 433 nla_put_u8(skb, TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE, 434 opt->type) || 435 nla_put(skb, TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA, 436 opt->length * 4, opt + 1)) { 437 nla_nest_cancel(skb, start); 438 return -EMSGSIZE; 439 } 440 441 len -= sizeof(struct geneve_opt) + opt->length * 4; 442 src += sizeof(struct geneve_opt) + opt->length * 4; 443 } 444 445 nla_nest_end(skb, start); 446 return 0; 447 } 448 449 static int tunnel_key_opts_dump(struct sk_buff *skb, 450 const struct ip_tunnel_info *info) 451 { 452 struct nlattr *start; 453 int err = -EINVAL; 454 455 if (!info->options_len) 456 return 0; 457 458 start = nla_nest_start(skb, TCA_TUNNEL_KEY_ENC_OPTS); 459 if (!start) 460 return -EMSGSIZE; 461 462 if (info->key.tun_flags & TUNNEL_GENEVE_OPT) { 463 err = tunnel_key_geneve_opts_dump(skb, info); 464 if (err) 465 goto err_out; 466 } else { 467 err_out: 468 nla_nest_cancel(skb, start); 469 return err; 470 } 471 472 nla_nest_end(skb, start); 473 return 0; 474 } 475 476 static int tunnel_key_dump_addresses(struct sk_buff *skb, 477 const struct ip_tunnel_info *info) 478 { 479 unsigned short family = ip_tunnel_info_af(info); 480 481 if (family == AF_INET) { 482 __be32 saddr = info->key.u.ipv4.src; 483 __be32 daddr = info->key.u.ipv4.dst; 484 485 if (!nla_put_in_addr(skb, TCA_TUNNEL_KEY_ENC_IPV4_SRC, saddr) && 486 !nla_put_in_addr(skb, TCA_TUNNEL_KEY_ENC_IPV4_DST, daddr)) 487 return 0; 488 } 489 490 if (family == AF_INET6) { 491 const struct in6_addr *saddr6 = &info->key.u.ipv6.src; 492 const struct in6_addr *daddr6 = &info->key.u.ipv6.dst; 493 494 if (!nla_put_in6_addr(skb, 495 TCA_TUNNEL_KEY_ENC_IPV6_SRC, saddr6) && 496 !nla_put_in6_addr(skb, 497 TCA_TUNNEL_KEY_ENC_IPV6_DST, daddr6)) 498 return 0; 499 } 500 501 return -EINVAL; 502 } 503 504 static int tunnel_key_dump(struct sk_buff *skb, struct tc_action *a, 505 int bind, int ref) 506 { 507 unsigned char *b = skb_tail_pointer(skb); 508 struct tcf_tunnel_key *t = to_tunnel_key(a); 509 struct tcf_tunnel_key_params *params; 510 struct tc_tunnel_key opt = { 511 .index = t->tcf_index, 512 .refcnt = refcount_read(&t->tcf_refcnt) - ref, 513 .bindcnt = atomic_read(&t->tcf_bindcnt) - bind, 514 }; 515 struct tcf_t tm; 516 517 spin_lock_bh(&t->tcf_lock); 518 params = rcu_dereference_protected(t->params, 519 lockdep_is_held(&t->tcf_lock)); 520 opt.action = t->tcf_action; 521 opt.t_action = params->tcft_action; 522 523 if (nla_put(skb, TCA_TUNNEL_KEY_PARMS, sizeof(opt), &opt)) 524 goto nla_put_failure; 525 526 if (params->tcft_action == TCA_TUNNEL_KEY_ACT_SET) { 527 struct ip_tunnel_info *info = 528 ¶ms->tcft_enc_metadata->u.tun_info; 529 struct ip_tunnel_key *key = &info->key; 530 __be32 key_id = tunnel_id_to_key32(key->tun_id); 531 532 if (((key->tun_flags & TUNNEL_KEY) && 533 nla_put_be32(skb, TCA_TUNNEL_KEY_ENC_KEY_ID, key_id)) || 534 tunnel_key_dump_addresses(skb, 535 ¶ms->tcft_enc_metadata->u.tun_info) || 536 (key->tp_dst && 537 nla_put_be16(skb, TCA_TUNNEL_KEY_ENC_DST_PORT, 538 key->tp_dst)) || 539 nla_put_u8(skb, TCA_TUNNEL_KEY_NO_CSUM, 540 !(key->tun_flags & TUNNEL_CSUM)) || 541 tunnel_key_opts_dump(skb, info)) 542 goto nla_put_failure; 543 544 if (key->tos && nla_put_u8(skb, TCA_TUNNEL_KEY_ENC_TOS, key->tos)) 545 goto nla_put_failure; 546 547 if (key->ttl && nla_put_u8(skb, TCA_TUNNEL_KEY_ENC_TTL, key->ttl)) 548 goto nla_put_failure; 549 } 550 551 tcf_tm_dump(&tm, &t->tcf_tm); 552 if (nla_put_64bit(skb, TCA_TUNNEL_KEY_TM, sizeof(tm), 553 &tm, TCA_TUNNEL_KEY_PAD)) 554 goto nla_put_failure; 555 spin_unlock_bh(&t->tcf_lock); 556 557 return skb->len; 558 559 nla_put_failure: 560 spin_unlock_bh(&t->tcf_lock); 561 nlmsg_trim(skb, b); 562 return -1; 563 } 564 565 static int tunnel_key_walker(struct net *net, struct sk_buff *skb, 566 struct netlink_callback *cb, int type, 567 const struct tc_action_ops *ops, 568 struct netlink_ext_ack *extack) 569 { 570 struct tc_action_net *tn = net_generic(net, tunnel_key_net_id); 571 572 return tcf_generic_walker(tn, skb, cb, type, ops, extack); 573 } 574 575 static int tunnel_key_search(struct net *net, struct tc_action **a, u32 index) 576 { 577 struct tc_action_net *tn = net_generic(net, tunnel_key_net_id); 578 579 return tcf_idr_search(tn, a, index); 580 } 581 582 static struct tc_action_ops act_tunnel_key_ops = { 583 .kind = "tunnel_key", 584 .id = TCA_ID_TUNNEL_KEY, 585 .owner = THIS_MODULE, 586 .act = tunnel_key_act, 587 .dump = tunnel_key_dump, 588 .init = tunnel_key_init, 589 .cleanup = tunnel_key_release, 590 .walk = tunnel_key_walker, 591 .lookup = tunnel_key_search, 592 .size = sizeof(struct tcf_tunnel_key), 593 }; 594 595 static __net_init int tunnel_key_init_net(struct net *net) 596 { 597 struct tc_action_net *tn = net_generic(net, tunnel_key_net_id); 598 599 return tc_action_net_init(tn, &act_tunnel_key_ops); 600 } 601 602 static void __net_exit tunnel_key_exit_net(struct list_head *net_list) 603 { 604 tc_action_net_exit(net_list, tunnel_key_net_id); 605 } 606 607 static struct pernet_operations tunnel_key_net_ops = { 608 .init = tunnel_key_init_net, 609 .exit_batch = tunnel_key_exit_net, 610 .id = &tunnel_key_net_id, 611 .size = sizeof(struct tc_action_net), 612 }; 613 614 static int __init tunnel_key_init_module(void) 615 { 616 return tcf_register_action(&act_tunnel_key_ops, &tunnel_key_net_ops); 617 } 618 619 static void __exit tunnel_key_cleanup_module(void) 620 { 621 tcf_unregister_action(&act_tunnel_key_ops, &tunnel_key_net_ops); 622 } 623 624 module_init(tunnel_key_init_module); 625 module_exit(tunnel_key_cleanup_module); 626 627 MODULE_AUTHOR("Amir Vadai <amir@vadai.me>"); 628 MODULE_DESCRIPTION("ip tunnel manipulation actions"); 629 MODULE_LICENSE("GPL v2"); 630