1 /* SPDX-License-Identifier: GPL-2.0 */ 2 #include <linux/kernel.h> 3 #include <linux/init.h> 4 #include <linux/module.h> 5 #include <linux/seqlock.h> 6 #include <linux/netlink.h> 7 #include <linux/netfilter.h> 8 #include <linux/netfilter/nf_tables.h> 9 #include <net/netfilter/nf_tables.h> 10 #include <net/dst_metadata.h> 11 #include <net/ip_tunnels.h> 12 #include <net/vxlan.h> 13 #include <net/erspan.h> 14 15 struct nft_tunnel { 16 enum nft_tunnel_keys key:8; 17 enum nft_registers dreg:8; 18 enum nft_tunnel_mode mode:8; 19 }; 20 21 static void nft_tunnel_get_eval(const struct nft_expr *expr, 22 struct nft_regs *regs, 23 const struct nft_pktinfo *pkt) 24 { 25 const struct nft_tunnel *priv = nft_expr_priv(expr); 26 u32 *dest = ®s->data[priv->dreg]; 27 struct ip_tunnel_info *tun_info; 28 29 tun_info = skb_tunnel_info(pkt->skb); 30 31 switch (priv->key) { 32 case NFT_TUNNEL_PATH: 33 if (!tun_info) { 34 nft_reg_store8(dest, false); 35 return; 36 } 37 if (priv->mode == NFT_TUNNEL_MODE_NONE || 38 (priv->mode == NFT_TUNNEL_MODE_RX && 39 !(tun_info->mode & IP_TUNNEL_INFO_TX)) || 40 (priv->mode == NFT_TUNNEL_MODE_TX && 41 (tun_info->mode & IP_TUNNEL_INFO_TX))) 42 nft_reg_store8(dest, true); 43 else 44 nft_reg_store8(dest, false); 45 break; 46 case NFT_TUNNEL_ID: 47 if (!tun_info) { 48 regs->verdict.code = NFT_BREAK; 49 return; 50 } 51 if (priv->mode == NFT_TUNNEL_MODE_NONE || 52 (priv->mode == NFT_TUNNEL_MODE_RX && 53 !(tun_info->mode & IP_TUNNEL_INFO_TX)) || 54 (priv->mode == NFT_TUNNEL_MODE_TX && 55 (tun_info->mode & IP_TUNNEL_INFO_TX))) 56 *dest = ntohl(tunnel_id_to_key32(tun_info->key.tun_id)); 57 else 58 regs->verdict.code = NFT_BREAK; 59 break; 60 default: 61 WARN_ON(1); 62 regs->verdict.code = NFT_BREAK; 63 } 64 } 65 66 static const struct nla_policy nft_tunnel_policy[NFTA_TUNNEL_MAX + 1] = { 67 [NFTA_TUNNEL_KEY] = { .type = NLA_U32 }, 68 [NFTA_TUNNEL_DREG] = { .type = NLA_U32 }, 69 [NFTA_TUNNEL_MODE] = { .type = NLA_U32 }, 70 }; 71 72 static int nft_tunnel_get_init(const struct nft_ctx *ctx, 73 const struct nft_expr *expr, 74 const struct nlattr * const tb[]) 75 { 76 struct nft_tunnel *priv = nft_expr_priv(expr); 77 u32 len; 78 79 if (!tb[NFTA_TUNNEL_KEY] && 80 !tb[NFTA_TUNNEL_DREG]) 81 return -EINVAL; 82 83 priv->key = ntohl(nla_get_be32(tb[NFTA_TUNNEL_KEY])); 84 switch (priv->key) { 85 case NFT_TUNNEL_PATH: 86 len = sizeof(u8); 87 break; 88 case NFT_TUNNEL_ID: 89 len = sizeof(u32); 90 break; 91 default: 92 return -EOPNOTSUPP; 93 } 94 95 priv->dreg = nft_parse_register(tb[NFTA_TUNNEL_DREG]); 96 97 if (tb[NFTA_TUNNEL_MODE]) { 98 priv->mode = ntohl(nla_get_be32(tb[NFTA_TUNNEL_MODE])); 99 if (priv->mode > NFT_TUNNEL_MODE_MAX) 100 return -EOPNOTSUPP; 101 } else { 102 priv->mode = NFT_TUNNEL_MODE_NONE; 103 } 104 105 return nft_validate_register_store(ctx, priv->dreg, NULL, 106 NFT_DATA_VALUE, len); 107 } 108 109 static int nft_tunnel_get_dump(struct sk_buff *skb, 110 const struct nft_expr *expr) 111 { 112 const struct nft_tunnel *priv = nft_expr_priv(expr); 113 114 if (nla_put_be32(skb, NFTA_TUNNEL_KEY, htonl(priv->key))) 115 goto nla_put_failure; 116 if (nft_dump_register(skb, NFTA_TUNNEL_DREG, priv->dreg)) 117 goto nla_put_failure; 118 if (nla_put_be32(skb, NFTA_TUNNEL_MODE, htonl(priv->mode))) 119 goto nla_put_failure; 120 return 0; 121 122 nla_put_failure: 123 return -1; 124 } 125 126 static struct nft_expr_type nft_tunnel_type; 127 static const struct nft_expr_ops nft_tunnel_get_ops = { 128 .type = &nft_tunnel_type, 129 .size = NFT_EXPR_SIZE(sizeof(struct nft_tunnel)), 130 .eval = nft_tunnel_get_eval, 131 .init = nft_tunnel_get_init, 132 .dump = nft_tunnel_get_dump, 133 }; 134 135 static struct nft_expr_type nft_tunnel_type __read_mostly = { 136 .name = "tunnel", 137 .ops = &nft_tunnel_get_ops, 138 .policy = nft_tunnel_policy, 139 .maxattr = NFTA_TUNNEL_MAX, 140 .owner = THIS_MODULE, 141 }; 142 143 struct nft_tunnel_opts { 144 union { 145 struct vxlan_metadata vxlan; 146 struct erspan_metadata erspan; 147 } u; 148 u32 len; 149 __be16 flags; 150 }; 151 152 struct nft_tunnel_obj { 153 struct metadata_dst *md; 154 struct nft_tunnel_opts opts; 155 }; 156 157 static const struct nla_policy nft_tunnel_ip_policy[NFTA_TUNNEL_KEY_IP_MAX + 1] = { 158 [NFTA_TUNNEL_KEY_IP_SRC] = { .type = NLA_U32 }, 159 [NFTA_TUNNEL_KEY_IP_DST] = { .type = NLA_U32 }, 160 }; 161 162 static int nft_tunnel_obj_ip_init(const struct nft_ctx *ctx, 163 const struct nlattr *attr, 164 struct ip_tunnel_info *info) 165 { 166 struct nlattr *tb[NFTA_TUNNEL_KEY_IP_MAX + 1]; 167 int err; 168 169 err = nla_parse_nested(tb, NFTA_TUNNEL_KEY_IP_MAX, attr, 170 nft_tunnel_ip_policy, NULL); 171 if (err < 0) 172 return err; 173 174 if (!tb[NFTA_TUNNEL_KEY_IP_DST]) 175 return -EINVAL; 176 177 if (tb[NFTA_TUNNEL_KEY_IP_SRC]) 178 info->key.u.ipv4.src = nla_get_be32(tb[NFTA_TUNNEL_KEY_IP_SRC]); 179 if (tb[NFTA_TUNNEL_KEY_IP_DST]) 180 info->key.u.ipv4.dst = nla_get_be32(tb[NFTA_TUNNEL_KEY_IP_DST]); 181 182 return 0; 183 } 184 185 static const struct nla_policy nft_tunnel_ip6_policy[NFTA_TUNNEL_KEY_IP6_MAX + 1] = { 186 [NFTA_TUNNEL_KEY_IP6_SRC] = { .len = sizeof(struct in6_addr), }, 187 [NFTA_TUNNEL_KEY_IP6_DST] = { .len = sizeof(struct in6_addr), }, 188 [NFTA_TUNNEL_KEY_IP6_FLOWLABEL] = { .type = NLA_U32, } 189 }; 190 191 static int nft_tunnel_obj_ip6_init(const struct nft_ctx *ctx, 192 const struct nlattr *attr, 193 struct ip_tunnel_info *info) 194 { 195 struct nlattr *tb[NFTA_TUNNEL_KEY_IP6_MAX + 1]; 196 int err; 197 198 err = nla_parse_nested(tb, NFTA_TUNNEL_KEY_IP6_MAX, attr, 199 nft_tunnel_ip6_policy, NULL); 200 if (err < 0) 201 return err; 202 203 if (!tb[NFTA_TUNNEL_KEY_IP6_DST]) 204 return -EINVAL; 205 206 if (tb[NFTA_TUNNEL_KEY_IP6_SRC]) { 207 memcpy(&info->key.u.ipv6.src, 208 nla_data(tb[NFTA_TUNNEL_KEY_IP6_SRC]), 209 sizeof(struct in6_addr)); 210 } 211 if (tb[NFTA_TUNNEL_KEY_IP6_DST]) { 212 memcpy(&info->key.u.ipv6.dst, 213 nla_data(tb[NFTA_TUNNEL_KEY_IP6_DST]), 214 sizeof(struct in6_addr)); 215 } 216 if (tb[NFTA_TUNNEL_KEY_IP6_FLOWLABEL]) 217 info->key.label = nla_get_be32(tb[NFTA_TUNNEL_KEY_IP6_FLOWLABEL]); 218 219 info->mode |= IP_TUNNEL_INFO_IPV6; 220 221 return 0; 222 } 223 224 static const struct nla_policy nft_tunnel_opts_vxlan_policy[NFTA_TUNNEL_KEY_VXLAN_MAX + 1] = { 225 [NFTA_TUNNEL_KEY_VXLAN_GBP] = { .type = NLA_U32 }, 226 }; 227 228 static int nft_tunnel_obj_vxlan_init(const struct nlattr *attr, 229 struct nft_tunnel_opts *opts) 230 { 231 struct nlattr *tb[NFTA_TUNNEL_KEY_VXLAN_MAX + 1]; 232 int err; 233 234 err = nla_parse_nested(tb, NFTA_TUNNEL_KEY_VXLAN_MAX, attr, 235 nft_tunnel_opts_vxlan_policy, NULL); 236 if (err < 0) 237 return err; 238 239 if (!tb[NFTA_TUNNEL_KEY_VXLAN_GBP]) 240 return -EINVAL; 241 242 opts->u.vxlan.gbp = ntohl(nla_get_be32(tb[NFTA_TUNNEL_KEY_VXLAN_GBP])); 243 244 opts->len = sizeof(struct vxlan_metadata); 245 opts->flags = TUNNEL_VXLAN_OPT; 246 247 return 0; 248 } 249 250 static const struct nla_policy nft_tunnel_opts_erspan_policy[NFTA_TUNNEL_KEY_ERSPAN_MAX + 1] = { 251 [NFTA_TUNNEL_KEY_ERSPAN_V1_INDEX] = { .type = NLA_U32 }, 252 [NFTA_TUNNEL_KEY_ERSPAN_V2_DIR] = { .type = NLA_U8 }, 253 [NFTA_TUNNEL_KEY_ERSPAN_V2_HWID] = { .type = NLA_U8 }, 254 }; 255 256 static int nft_tunnel_obj_erspan_init(const struct nlattr *attr, 257 struct nft_tunnel_opts *opts) 258 { 259 struct nlattr *tb[NFTA_TUNNEL_KEY_ERSPAN_MAX + 1]; 260 uint8_t hwid, dir; 261 int err, version; 262 263 err = nla_parse_nested(tb, NFTA_TUNNEL_KEY_ERSPAN_MAX, attr, 264 nft_tunnel_opts_erspan_policy, NULL); 265 if (err < 0) 266 return err; 267 268 version = ntohl(nla_get_be32(tb[NFTA_TUNNEL_KEY_ERSPAN_VERSION])); 269 switch (version) { 270 case ERSPAN_VERSION: 271 if (!tb[NFTA_TUNNEL_KEY_ERSPAN_V1_INDEX]) 272 return -EINVAL; 273 274 opts->u.erspan.u.index = 275 nla_get_be32(tb[NFTA_TUNNEL_KEY_ERSPAN_V1_INDEX]); 276 break; 277 case ERSPAN_VERSION2: 278 if (!tb[NFTA_TUNNEL_KEY_ERSPAN_V2_DIR] || 279 !tb[NFTA_TUNNEL_KEY_ERSPAN_V2_HWID]) 280 return -EINVAL; 281 282 hwid = nla_get_u8(tb[NFTA_TUNNEL_KEY_ERSPAN_V2_HWID]); 283 dir = nla_get_u8(tb[NFTA_TUNNEL_KEY_ERSPAN_V2_DIR]); 284 285 set_hwid(&opts->u.erspan.u.md2, hwid); 286 opts->u.erspan.u.md2.dir = dir; 287 break; 288 default: 289 return -EOPNOTSUPP; 290 } 291 opts->u.erspan.version = version; 292 293 opts->len = sizeof(struct erspan_metadata); 294 opts->flags = TUNNEL_ERSPAN_OPT; 295 296 return 0; 297 } 298 299 static const struct nla_policy nft_tunnel_opts_policy[NFTA_TUNNEL_KEY_OPTS_MAX + 1] = { 300 [NFTA_TUNNEL_KEY_OPTS_VXLAN] = { .type = NLA_NESTED, }, 301 [NFTA_TUNNEL_KEY_OPTS_ERSPAN] = { .type = NLA_NESTED, }, 302 }; 303 304 static int nft_tunnel_obj_opts_init(const struct nft_ctx *ctx, 305 const struct nlattr *attr, 306 struct ip_tunnel_info *info, 307 struct nft_tunnel_opts *opts) 308 { 309 struct nlattr *tb[NFTA_TUNNEL_KEY_OPTS_MAX + 1]; 310 int err; 311 312 err = nla_parse_nested(tb, NFTA_TUNNEL_KEY_OPTS_MAX, attr, 313 nft_tunnel_opts_policy, NULL); 314 if (err < 0) 315 return err; 316 317 if (tb[NFTA_TUNNEL_KEY_OPTS_VXLAN]) { 318 err = nft_tunnel_obj_vxlan_init(tb[NFTA_TUNNEL_KEY_OPTS_VXLAN], 319 opts); 320 } else if (tb[NFTA_TUNNEL_KEY_OPTS_ERSPAN]) { 321 err = nft_tunnel_obj_erspan_init(tb[NFTA_TUNNEL_KEY_OPTS_ERSPAN], 322 opts); 323 } else { 324 return -EOPNOTSUPP; 325 } 326 327 return err; 328 } 329 330 static const struct nla_policy nft_tunnel_key_policy[NFTA_TUNNEL_KEY_MAX + 1] = { 331 [NFTA_TUNNEL_KEY_IP] = { .type = NLA_NESTED, }, 332 [NFTA_TUNNEL_KEY_IP6] = { .type = NLA_NESTED, }, 333 [NFTA_TUNNEL_KEY_ID] = { .type = NLA_U32, }, 334 [NFTA_TUNNEL_KEY_FLAGS] = { .type = NLA_U32, }, 335 [NFTA_TUNNEL_KEY_TOS] = { .type = NLA_U8, }, 336 [NFTA_TUNNEL_KEY_TTL] = { .type = NLA_U8, }, 337 [NFTA_TUNNEL_KEY_OPTS] = { .type = NLA_NESTED, }, 338 }; 339 340 static int nft_tunnel_obj_init(const struct nft_ctx *ctx, 341 const struct nlattr * const tb[], 342 struct nft_object *obj) 343 { 344 struct nft_tunnel_obj *priv = nft_obj_data(obj); 345 struct ip_tunnel_info info; 346 struct metadata_dst *md; 347 int err; 348 349 if (!tb[NFTA_TUNNEL_KEY_ID]) 350 return -EINVAL; 351 352 memset(&info, 0, sizeof(info)); 353 info.mode = IP_TUNNEL_INFO_TX; 354 info.key.tun_id = key32_to_tunnel_id(nla_get_be32(tb[NFTA_TUNNEL_KEY_ID])); 355 info.key.tun_flags = TUNNEL_KEY | TUNNEL_CSUM | TUNNEL_NOCACHE; 356 357 if (tb[NFTA_TUNNEL_KEY_IP]) { 358 err = nft_tunnel_obj_ip_init(ctx, tb[NFTA_TUNNEL_KEY_IP], &info); 359 if (err < 0) 360 return err; 361 } else if (tb[NFTA_TUNNEL_KEY_IP6]) { 362 err = nft_tunnel_obj_ip6_init(ctx, tb[NFTA_TUNNEL_KEY_IP6], &info); 363 if (err < 0) 364 return err; 365 } else { 366 return -EINVAL; 367 } 368 369 if (tb[NFTA_TUNNEL_KEY_SPORT]) { 370 info.key.tp_src = nla_get_be16(tb[NFTA_TUNNEL_KEY_SPORT]); 371 } 372 if (tb[NFTA_TUNNEL_KEY_DPORT]) { 373 info.key.tp_dst = nla_get_be16(tb[NFTA_TUNNEL_KEY_DPORT]); 374 } 375 376 if (tb[NFTA_TUNNEL_KEY_FLAGS]) { 377 u32 tun_flags; 378 379 tun_flags = ntohl(nla_get_be32(tb[NFTA_TUNNEL_KEY_FLAGS])); 380 if (tun_flags & ~NFT_TUNNEL_F_MASK) 381 return -EOPNOTSUPP; 382 383 if (tun_flags & NFT_TUNNEL_F_ZERO_CSUM_TX) 384 info.key.tun_flags &= ~TUNNEL_CSUM; 385 if (tun_flags & NFT_TUNNEL_F_DONT_FRAGMENT) 386 info.key.tun_flags |= TUNNEL_DONT_FRAGMENT; 387 if (tun_flags & NFT_TUNNEL_F_SEQ_NUMBER) 388 info.key.tun_flags |= TUNNEL_SEQ; 389 } 390 if (tb[NFTA_TUNNEL_KEY_TOS]) 391 info.key.tos = nla_get_u8(tb[NFTA_TUNNEL_KEY_TOS]); 392 if (tb[NFTA_TUNNEL_KEY_TTL]) 393 info.key.ttl = nla_get_u8(tb[NFTA_TUNNEL_KEY_TTL]); 394 else 395 info.key.ttl = U8_MAX; 396 397 if (tb[NFTA_TUNNEL_KEY_OPTS]) { 398 err = nft_tunnel_obj_opts_init(ctx, tb[NFTA_TUNNEL_KEY_OPTS], 399 &info, &priv->opts); 400 if (err < 0) 401 return err; 402 } 403 404 md = metadata_dst_alloc(priv->opts.len, METADATA_IP_TUNNEL, GFP_KERNEL); 405 if (!md) 406 return -ENOMEM; 407 408 memcpy(&md->u.tun_info, &info, sizeof(info)); 409 #ifdef CONFIG_DST_CACHE 410 err = dst_cache_init(&md->u.tun_info.dst_cache, GFP_KERNEL); 411 if (err < 0) { 412 metadata_dst_free(md); 413 return err; 414 } 415 #endif 416 ip_tunnel_info_opts_set(&md->u.tun_info, &priv->opts.u, priv->opts.len, 417 priv->opts.flags); 418 priv->md = md; 419 420 return 0; 421 } 422 423 static inline void nft_tunnel_obj_eval(struct nft_object *obj, 424 struct nft_regs *regs, 425 const struct nft_pktinfo *pkt) 426 { 427 struct nft_tunnel_obj *priv = nft_obj_data(obj); 428 struct sk_buff *skb = pkt->skb; 429 430 skb_dst_drop(skb); 431 dst_hold((struct dst_entry *) priv->md); 432 skb_dst_set(skb, (struct dst_entry *) priv->md); 433 } 434 435 static int nft_tunnel_ip_dump(struct sk_buff *skb, struct ip_tunnel_info *info) 436 { 437 struct nlattr *nest; 438 439 if (info->mode & IP_TUNNEL_INFO_IPV6) { 440 nest = nla_nest_start(skb, NFTA_TUNNEL_KEY_IP6); 441 if (!nest) 442 return -1; 443 444 if (nla_put_in6_addr(skb, NFTA_TUNNEL_KEY_IP6_SRC, &info->key.u.ipv6.src) < 0 || 445 nla_put_in6_addr(skb, NFTA_TUNNEL_KEY_IP6_DST, &info->key.u.ipv6.dst) < 0 || 446 nla_put_be32(skb, NFTA_TUNNEL_KEY_IP6_FLOWLABEL, info->key.label)) 447 return -1; 448 449 nla_nest_end(skb, nest); 450 } else { 451 nest = nla_nest_start(skb, NFTA_TUNNEL_KEY_IP); 452 if (!nest) 453 return -1; 454 455 if (nla_put_in_addr(skb, NFTA_TUNNEL_KEY_IP_SRC, info->key.u.ipv4.src) < 0 || 456 nla_put_in_addr(skb, NFTA_TUNNEL_KEY_IP_DST, info->key.u.ipv4.dst) < 0) 457 return -1; 458 459 nla_nest_end(skb, nest); 460 } 461 462 return 0; 463 } 464 465 static int nft_tunnel_opts_dump(struct sk_buff *skb, 466 struct nft_tunnel_obj *priv) 467 { 468 struct nft_tunnel_opts *opts = &priv->opts; 469 struct nlattr *nest; 470 471 nest = nla_nest_start(skb, NFTA_TUNNEL_KEY_OPTS); 472 if (!nest) 473 return -1; 474 475 if (opts->flags & TUNNEL_VXLAN_OPT) { 476 if (nla_put_be32(skb, NFTA_TUNNEL_KEY_VXLAN_GBP, 477 htonl(opts->u.vxlan.gbp))) 478 return -1; 479 } else if (opts->flags & TUNNEL_ERSPAN_OPT) { 480 switch (opts->u.erspan.version) { 481 case ERSPAN_VERSION: 482 if (nla_put_be32(skb, NFTA_TUNNEL_KEY_ERSPAN_V1_INDEX, 483 opts->u.erspan.u.index)) 484 return -1; 485 break; 486 case ERSPAN_VERSION2: 487 if (nla_put_u8(skb, NFTA_TUNNEL_KEY_ERSPAN_V2_HWID, 488 get_hwid(&opts->u.erspan.u.md2)) || 489 nla_put_u8(skb, NFTA_TUNNEL_KEY_ERSPAN_V2_DIR, 490 opts->u.erspan.u.md2.dir)) 491 return -1; 492 break; 493 } 494 } 495 nla_nest_end(skb, nest); 496 497 return 0; 498 } 499 500 static int nft_tunnel_ports_dump(struct sk_buff *skb, 501 struct ip_tunnel_info *info) 502 { 503 if (nla_put_be16(skb, NFTA_TUNNEL_KEY_SPORT, htons(info->key.tp_src)) < 0 || 504 nla_put_be16(skb, NFTA_TUNNEL_KEY_DPORT, htons(info->key.tp_dst)) < 0) 505 return -1; 506 507 return 0; 508 } 509 510 static int nft_tunnel_flags_dump(struct sk_buff *skb, 511 struct ip_tunnel_info *info) 512 { 513 u32 flags = 0; 514 515 if (info->key.tun_flags & TUNNEL_DONT_FRAGMENT) 516 flags |= NFT_TUNNEL_F_DONT_FRAGMENT; 517 if (!(info->key.tun_flags & TUNNEL_CSUM)) 518 flags |= NFT_TUNNEL_F_ZERO_CSUM_TX; 519 if (info->key.tun_flags & TUNNEL_SEQ) 520 flags |= NFT_TUNNEL_F_SEQ_NUMBER; 521 522 if (nla_put_be32(skb, NFTA_TUNNEL_KEY_FLAGS, htonl(flags)) < 0) 523 return -1; 524 525 return 0; 526 } 527 528 static int nft_tunnel_obj_dump(struct sk_buff *skb, 529 struct nft_object *obj, bool reset) 530 { 531 struct nft_tunnel_obj *priv = nft_obj_data(obj); 532 struct ip_tunnel_info *info = &priv->md->u.tun_info; 533 534 if (nla_put_be32(skb, NFTA_TUNNEL_KEY_ID, 535 tunnel_id_to_key32(info->key.tun_id)) || 536 nft_tunnel_ip_dump(skb, info) < 0 || 537 nft_tunnel_ports_dump(skb, info) < 0 || 538 nft_tunnel_flags_dump(skb, info) < 0 || 539 nla_put_u8(skb, NFTA_TUNNEL_KEY_TOS, info->key.tos) || 540 nla_put_u8(skb, NFTA_TUNNEL_KEY_TTL, info->key.ttl) || 541 nft_tunnel_opts_dump(skb, priv) < 0) 542 goto nla_put_failure; 543 544 return 0; 545 546 nla_put_failure: 547 return -1; 548 } 549 550 static void nft_tunnel_obj_destroy(const struct nft_ctx *ctx, 551 struct nft_object *obj) 552 { 553 struct nft_tunnel_obj *priv = nft_obj_data(obj); 554 555 metadata_dst_free(priv->md); 556 } 557 558 static struct nft_object_type nft_tunnel_obj_type; 559 static const struct nft_object_ops nft_tunnel_obj_ops = { 560 .type = &nft_tunnel_obj_type, 561 .size = sizeof(struct nft_tunnel_obj), 562 .eval = nft_tunnel_obj_eval, 563 .init = nft_tunnel_obj_init, 564 .destroy = nft_tunnel_obj_destroy, 565 .dump = nft_tunnel_obj_dump, 566 }; 567 568 static struct nft_object_type nft_tunnel_obj_type __read_mostly = { 569 .type = NFT_OBJECT_TUNNEL, 570 .ops = &nft_tunnel_obj_ops, 571 .maxattr = NFTA_TUNNEL_KEY_MAX, 572 .policy = nft_tunnel_key_policy, 573 .owner = THIS_MODULE, 574 }; 575 576 static int __init nft_tunnel_module_init(void) 577 { 578 int err; 579 580 err = nft_register_expr(&nft_tunnel_type); 581 if (err < 0) 582 return err; 583 584 err = nft_register_obj(&nft_tunnel_obj_type); 585 if (err < 0) 586 nft_unregister_expr(&nft_tunnel_type); 587 588 return err; 589 } 590 591 static void __exit nft_tunnel_module_exit(void) 592 { 593 nft_unregister_obj(&nft_tunnel_obj_type); 594 nft_unregister_expr(&nft_tunnel_type); 595 } 596 597 module_init(nft_tunnel_module_init); 598 module_exit(nft_tunnel_module_exit); 599 600 MODULE_LICENSE("GPL"); 601 MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>"); 602 MODULE_ALIAS_NFT_EXPR("tunnel"); 603 MODULE_ALIAS_NFT_OBJ(NFT_OBJECT_TUNNEL); 604