196518518SPatrick McHardy /* 2ef1f7df9SPatrick McHardy * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net> 396518518SPatrick McHardy * 496518518SPatrick McHardy * This program is free software; you can redistribute it and/or modify 596518518SPatrick McHardy * it under the terms of the GNU General Public License version 2 as 696518518SPatrick McHardy * published by the Free Software Foundation. 796518518SPatrick McHardy * 896518518SPatrick McHardy * Development of this code funded by Astaro AG (http://www.astaro.com/) 996518518SPatrick McHardy */ 1096518518SPatrick McHardy 1196518518SPatrick McHardy #include <linux/kernel.h> 1296518518SPatrick McHardy #include <linux/init.h> 1396518518SPatrick McHardy #include <linux/module.h> 1496518518SPatrick McHardy #include <linux/netlink.h> 1596518518SPatrick McHardy #include <linux/netfilter.h> 1696518518SPatrick McHardy #include <linux/netfilter/nf_tables.h> 17e2a093ffSAna Rey #include <linux/in.h> 18e2a093ffSAna Rey #include <linux/ip.h> 19e2a093ffSAna Rey #include <linux/ipv6.h> 20afc5be30SAna Rey #include <linux/smp.h> 2196518518SPatrick McHardy #include <net/dst.h> 2296518518SPatrick McHardy #include <net/sock.h> 2396518518SPatrick McHardy #include <net/tcp_states.h> /* for TCP_TIME_WAIT */ 2496518518SPatrick McHardy #include <net/netfilter/nf_tables.h> 25aa45660cSTomasz Bursztyka #include <net/netfilter/nft_meta.h> 2696518518SPatrick McHardy 27aa45660cSTomasz Bursztyka void nft_meta_get_eval(const struct nft_expr *expr, 2896518518SPatrick McHardy struct nft_data data[NFT_REG_MAX + 1], 2996518518SPatrick McHardy const struct nft_pktinfo *pkt) 3096518518SPatrick McHardy { 3196518518SPatrick McHardy const struct nft_meta *priv = nft_expr_priv(expr); 3296518518SPatrick McHardy const struct sk_buff *skb = pkt->skb; 3396518518SPatrick McHardy const struct net_device *in = pkt->in, *out = pkt->out; 3496518518SPatrick McHardy struct nft_data *dest = &data[priv->dreg]; 3596518518SPatrick McHardy 3696518518SPatrick McHardy switch (priv->key) { 3796518518SPatrick McHardy case NFT_META_LEN: 3896518518SPatrick McHardy dest->data[0] = skb->len; 3996518518SPatrick McHardy break; 4096518518SPatrick McHardy case NFT_META_PROTOCOL: 4196518518SPatrick McHardy *(__be16 *)dest->data = skb->protocol; 4296518518SPatrick McHardy break; 43124edfa9SPatrick McHardy case NFT_META_NFPROTO: 44124edfa9SPatrick McHardy dest->data[0] = pkt->ops->pf; 45124edfa9SPatrick McHardy break; 464566bf27SPatrick McHardy case NFT_META_L4PROTO: 474566bf27SPatrick McHardy dest->data[0] = pkt->tprot; 484566bf27SPatrick McHardy break; 4996518518SPatrick McHardy case NFT_META_PRIORITY: 5096518518SPatrick McHardy dest->data[0] = skb->priority; 5196518518SPatrick McHardy break; 5296518518SPatrick McHardy case NFT_META_MARK: 5396518518SPatrick McHardy dest->data[0] = skb->mark; 5496518518SPatrick McHardy break; 5596518518SPatrick McHardy case NFT_META_IIF: 5696518518SPatrick McHardy if (in == NULL) 5796518518SPatrick McHardy goto err; 5896518518SPatrick McHardy dest->data[0] = in->ifindex; 5996518518SPatrick McHardy break; 6096518518SPatrick McHardy case NFT_META_OIF: 6196518518SPatrick McHardy if (out == NULL) 6296518518SPatrick McHardy goto err; 6396518518SPatrick McHardy dest->data[0] = out->ifindex; 6496518518SPatrick McHardy break; 6596518518SPatrick McHardy case NFT_META_IIFNAME: 6696518518SPatrick McHardy if (in == NULL) 6796518518SPatrick McHardy goto err; 6896518518SPatrick McHardy strncpy((char *)dest->data, in->name, sizeof(dest->data)); 6996518518SPatrick McHardy break; 7096518518SPatrick McHardy case NFT_META_OIFNAME: 7196518518SPatrick McHardy if (out == NULL) 7296518518SPatrick McHardy goto err; 7396518518SPatrick McHardy strncpy((char *)dest->data, out->name, sizeof(dest->data)); 7496518518SPatrick McHardy break; 7596518518SPatrick McHardy case NFT_META_IIFTYPE: 7696518518SPatrick McHardy if (in == NULL) 7796518518SPatrick McHardy goto err; 7896518518SPatrick McHardy *(u16 *)dest->data = in->type; 7996518518SPatrick McHardy break; 8096518518SPatrick McHardy case NFT_META_OIFTYPE: 8196518518SPatrick McHardy if (out == NULL) 8296518518SPatrick McHardy goto err; 8396518518SPatrick McHardy *(u16 *)dest->data = out->type; 8496518518SPatrick McHardy break; 8596518518SPatrick McHardy case NFT_META_SKUID: 8696518518SPatrick McHardy if (skb->sk == NULL || skb->sk->sk_state == TCP_TIME_WAIT) 8796518518SPatrick McHardy goto err; 8896518518SPatrick McHardy 8996518518SPatrick McHardy read_lock_bh(&skb->sk->sk_callback_lock); 9096518518SPatrick McHardy if (skb->sk->sk_socket == NULL || 9196518518SPatrick McHardy skb->sk->sk_socket->file == NULL) { 9296518518SPatrick McHardy read_unlock_bh(&skb->sk->sk_callback_lock); 9396518518SPatrick McHardy goto err; 9496518518SPatrick McHardy } 9596518518SPatrick McHardy 9696518518SPatrick McHardy dest->data[0] = 9796518518SPatrick McHardy from_kuid_munged(&init_user_ns, 9896518518SPatrick McHardy skb->sk->sk_socket->file->f_cred->fsuid); 9996518518SPatrick McHardy read_unlock_bh(&skb->sk->sk_callback_lock); 10096518518SPatrick McHardy break; 10196518518SPatrick McHardy case NFT_META_SKGID: 10296518518SPatrick McHardy if (skb->sk == NULL || skb->sk->sk_state == TCP_TIME_WAIT) 10396518518SPatrick McHardy goto err; 10496518518SPatrick McHardy 10596518518SPatrick McHardy read_lock_bh(&skb->sk->sk_callback_lock); 10696518518SPatrick McHardy if (skb->sk->sk_socket == NULL || 10796518518SPatrick McHardy skb->sk->sk_socket->file == NULL) { 10896518518SPatrick McHardy read_unlock_bh(&skb->sk->sk_callback_lock); 10996518518SPatrick McHardy goto err; 11096518518SPatrick McHardy } 11196518518SPatrick McHardy dest->data[0] = 11296518518SPatrick McHardy from_kgid_munged(&init_user_ns, 11396518518SPatrick McHardy skb->sk->sk_socket->file->f_cred->fsgid); 11496518518SPatrick McHardy read_unlock_bh(&skb->sk->sk_callback_lock); 11596518518SPatrick McHardy break; 11606efbd6dSPaul Bolle #ifdef CONFIG_IP_ROUTE_CLASSID 11796518518SPatrick McHardy case NFT_META_RTCLASSID: { 11896518518SPatrick McHardy const struct dst_entry *dst = skb_dst(skb); 11996518518SPatrick McHardy 12096518518SPatrick McHardy if (dst == NULL) 12196518518SPatrick McHardy goto err; 12296518518SPatrick McHardy dest->data[0] = dst->tclassid; 12396518518SPatrick McHardy break; 12496518518SPatrick McHardy } 12596518518SPatrick McHardy #endif 12696518518SPatrick McHardy #ifdef CONFIG_NETWORK_SECMARK 12796518518SPatrick McHardy case NFT_META_SECMARK: 12896518518SPatrick McHardy dest->data[0] = skb->secmark; 12996518518SPatrick McHardy break; 13096518518SPatrick McHardy #endif 131e2a093ffSAna Rey case NFT_META_PKTTYPE: 132e2a093ffSAna Rey if (skb->pkt_type != PACKET_LOOPBACK) { 133e2a093ffSAna Rey dest->data[0] = skb->pkt_type; 134e2a093ffSAna Rey break; 135e2a093ffSAna Rey } 136e2a093ffSAna Rey 137e2a093ffSAna Rey switch (pkt->ops->pf) { 138e2a093ffSAna Rey case NFPROTO_IPV4: 139e2a093ffSAna Rey if (ipv4_is_multicast(ip_hdr(skb)->daddr)) 140e2a093ffSAna Rey dest->data[0] = PACKET_MULTICAST; 141e2a093ffSAna Rey else 142e2a093ffSAna Rey dest->data[0] = PACKET_BROADCAST; 143e2a093ffSAna Rey break; 144e2a093ffSAna Rey case NFPROTO_IPV6: 145e2a093ffSAna Rey if (ipv6_hdr(skb)->daddr.s6_addr[0] == 0xFF) 146e2a093ffSAna Rey dest->data[0] = PACKET_MULTICAST; 147e2a093ffSAna Rey else 148e2a093ffSAna Rey dest->data[0] = PACKET_BROADCAST; 149e2a093ffSAna Rey break; 150e2a093ffSAna Rey default: 151e2a093ffSAna Rey WARN_ON(1); 152e2a093ffSAna Rey goto err; 153e2a093ffSAna Rey } 154e2a093ffSAna Rey break; 155afc5be30SAna Rey case NFT_META_CPU: 156afc5be30SAna Rey dest->data[0] = smp_processor_id(); 157afc5be30SAna Rey break; 1583045d760SAna Rey case NFT_META_IIFGROUP: 1593045d760SAna Rey if (in == NULL) 1603045d760SAna Rey goto err; 1613045d760SAna Rey dest->data[0] = in->group; 1623045d760SAna Rey break; 1633045d760SAna Rey case NFT_META_OIFGROUP: 1643045d760SAna Rey if (out == NULL) 1653045d760SAna Rey goto err; 1663045d760SAna Rey dest->data[0] = out->group; 1673045d760SAna Rey break; 168ce674173SAna Rey case NFT_META_CGROUP: 169ce674173SAna Rey if (skb->sk == NULL) 170ce674173SAna Rey break; 171ce674173SAna Rey 172ce674173SAna Rey dest->data[0] = skb->sk->sk_classid; 173ce674173SAna Rey break; 17496518518SPatrick McHardy default: 17596518518SPatrick McHardy WARN_ON(1); 17696518518SPatrick McHardy goto err; 17796518518SPatrick McHardy } 17896518518SPatrick McHardy return; 17996518518SPatrick McHardy 18096518518SPatrick McHardy err: 18196518518SPatrick McHardy data[NFT_REG_VERDICT].verdict = NFT_BREAK; 18296518518SPatrick McHardy } 183aa45660cSTomasz Bursztyka EXPORT_SYMBOL_GPL(nft_meta_get_eval); 18496518518SPatrick McHardy 185aa45660cSTomasz Bursztyka void nft_meta_set_eval(const struct nft_expr *expr, 186e035b77aSArturo Borrero Gonzalez struct nft_data data[NFT_REG_MAX + 1], 187e035b77aSArturo Borrero Gonzalez const struct nft_pktinfo *pkt) 188e035b77aSArturo Borrero Gonzalez { 189e035b77aSArturo Borrero Gonzalez const struct nft_meta *meta = nft_expr_priv(expr); 190e035b77aSArturo Borrero Gonzalez struct sk_buff *skb = pkt->skb; 191e035b77aSArturo Borrero Gonzalez u32 value = data[meta->sreg].data[0]; 192e035b77aSArturo Borrero Gonzalez 193e035b77aSArturo Borrero Gonzalez switch (meta->key) { 194e035b77aSArturo Borrero Gonzalez case NFT_META_MARK: 195e035b77aSArturo Borrero Gonzalez skb->mark = value; 196e035b77aSArturo Borrero Gonzalez break; 197e035b77aSArturo Borrero Gonzalez case NFT_META_PRIORITY: 198e035b77aSArturo Borrero Gonzalez skb->priority = value; 199e035b77aSArturo Borrero Gonzalez break; 200e035b77aSArturo Borrero Gonzalez case NFT_META_NFTRACE: 201e035b77aSArturo Borrero Gonzalez skb->nf_trace = 1; 202e035b77aSArturo Borrero Gonzalez break; 203e035b77aSArturo Borrero Gonzalez default: 204e035b77aSArturo Borrero Gonzalez WARN_ON(1); 205e035b77aSArturo Borrero Gonzalez } 206e035b77aSArturo Borrero Gonzalez } 207aa45660cSTomasz Bursztyka EXPORT_SYMBOL_GPL(nft_meta_set_eval); 208e035b77aSArturo Borrero Gonzalez 209aa45660cSTomasz Bursztyka const struct nla_policy nft_meta_policy[NFTA_META_MAX + 1] = { 21096518518SPatrick McHardy [NFTA_META_DREG] = { .type = NLA_U32 }, 21196518518SPatrick McHardy [NFTA_META_KEY] = { .type = NLA_U32 }, 212e035b77aSArturo Borrero Gonzalez [NFTA_META_SREG] = { .type = NLA_U32 }, 21396518518SPatrick McHardy }; 214aa45660cSTomasz Bursztyka EXPORT_SYMBOL_GPL(nft_meta_policy); 21596518518SPatrick McHardy 216aa45660cSTomasz Bursztyka int nft_meta_get_init(const struct nft_ctx *ctx, 217d2caa696SPatrick McHardy const struct nft_expr *expr, 218d2caa696SPatrick McHardy const struct nlattr * const tb[]) 21996518518SPatrick McHardy { 220d2caa696SPatrick McHardy struct nft_meta *priv = nft_expr_priv(expr); 221d2caa696SPatrick McHardy int err; 22296518518SPatrick McHardy 223d2caa696SPatrick McHardy priv->key = ntohl(nla_get_be32(tb[NFTA_META_KEY])); 224d2caa696SPatrick McHardy switch (priv->key) { 22596518518SPatrick McHardy case NFT_META_LEN: 22696518518SPatrick McHardy case NFT_META_PROTOCOL: 227124edfa9SPatrick McHardy case NFT_META_NFPROTO: 2284566bf27SPatrick McHardy case NFT_META_L4PROTO: 22996518518SPatrick McHardy case NFT_META_PRIORITY: 23096518518SPatrick McHardy case NFT_META_MARK: 23196518518SPatrick McHardy case NFT_META_IIF: 23296518518SPatrick McHardy case NFT_META_OIF: 23396518518SPatrick McHardy case NFT_META_IIFNAME: 23496518518SPatrick McHardy case NFT_META_OIFNAME: 23596518518SPatrick McHardy case NFT_META_IIFTYPE: 23696518518SPatrick McHardy case NFT_META_OIFTYPE: 23796518518SPatrick McHardy case NFT_META_SKUID: 23896518518SPatrick McHardy case NFT_META_SKGID: 23906efbd6dSPaul Bolle #ifdef CONFIG_IP_ROUTE_CLASSID 24096518518SPatrick McHardy case NFT_META_RTCLASSID: 24196518518SPatrick McHardy #endif 24296518518SPatrick McHardy #ifdef CONFIG_NETWORK_SECMARK 24396518518SPatrick McHardy case NFT_META_SECMARK: 24496518518SPatrick McHardy #endif 245e2a093ffSAna Rey case NFT_META_PKTTYPE: 246afc5be30SAna Rey case NFT_META_CPU: 2473045d760SAna Rey case NFT_META_IIFGROUP: 2483045d760SAna Rey case NFT_META_OIFGROUP: 249ce674173SAna Rey case NFT_META_CGROUP: 250d2caa696SPatrick McHardy break; 25196518518SPatrick McHardy default: 25296518518SPatrick McHardy return -EOPNOTSUPP; 25396518518SPatrick McHardy } 25496518518SPatrick McHardy 25596518518SPatrick McHardy priv->dreg = ntohl(nla_get_be32(tb[NFTA_META_DREG])); 25696518518SPatrick McHardy err = nft_validate_output_register(priv->dreg); 25796518518SPatrick McHardy if (err < 0) 25896518518SPatrick McHardy return err; 259e035b77aSArturo Borrero Gonzalez 260d2caa696SPatrick McHardy err = nft_validate_data_load(ctx, priv->dreg, NULL, NFT_DATA_VALUE); 261e035b77aSArturo Borrero Gonzalez if (err < 0) 262e035b77aSArturo Borrero Gonzalez return err; 263e035b77aSArturo Borrero Gonzalez 264d2caa696SPatrick McHardy return 0; 265d2caa696SPatrick McHardy } 266aa45660cSTomasz Bursztyka EXPORT_SYMBOL_GPL(nft_meta_get_init); 267d2caa696SPatrick McHardy 268aa45660cSTomasz Bursztyka int nft_meta_set_init(const struct nft_ctx *ctx, 269d2caa696SPatrick McHardy const struct nft_expr *expr, 270d2caa696SPatrick McHardy const struct nlattr * const tb[]) 271d2caa696SPatrick McHardy { 272d2caa696SPatrick McHardy struct nft_meta *priv = nft_expr_priv(expr); 273d2caa696SPatrick McHardy int err; 274d2caa696SPatrick McHardy 275d2caa696SPatrick McHardy priv->key = ntohl(nla_get_be32(tb[NFTA_META_KEY])); 276d2caa696SPatrick McHardy switch (priv->key) { 277d2caa696SPatrick McHardy case NFT_META_MARK: 278d2caa696SPatrick McHardy case NFT_META_PRIORITY: 279d2caa696SPatrick McHardy case NFT_META_NFTRACE: 280d2caa696SPatrick McHardy break; 281d2caa696SPatrick McHardy default: 282d2caa696SPatrick McHardy return -EOPNOTSUPP; 283d2caa696SPatrick McHardy } 284d2caa696SPatrick McHardy 285e035b77aSArturo Borrero Gonzalez priv->sreg = ntohl(nla_get_be32(tb[NFTA_META_SREG])); 286b38895c5SPablo Neira Ayuso err = nft_validate_input_register(priv->sreg); 287b38895c5SPablo Neira Ayuso if (err < 0) 288b38895c5SPablo Neira Ayuso return err; 289e035b77aSArturo Borrero Gonzalez 290e035b77aSArturo Borrero Gonzalez return 0; 291e035b77aSArturo Borrero Gonzalez } 292aa45660cSTomasz Bursztyka EXPORT_SYMBOL_GPL(nft_meta_set_init); 293e035b77aSArturo Borrero Gonzalez 294aa45660cSTomasz Bursztyka int nft_meta_get_dump(struct sk_buff *skb, 295e035b77aSArturo Borrero Gonzalez const struct nft_expr *expr) 29696518518SPatrick McHardy { 29796518518SPatrick McHardy const struct nft_meta *priv = nft_expr_priv(expr); 29896518518SPatrick McHardy 29996518518SPatrick McHardy if (nla_put_be32(skb, NFTA_META_KEY, htonl(priv->key))) 30096518518SPatrick McHardy goto nla_put_failure; 301e035b77aSArturo Borrero Gonzalez if (nla_put_be32(skb, NFTA_META_DREG, htonl(priv->dreg))) 302e035b77aSArturo Borrero Gonzalez goto nla_put_failure; 30396518518SPatrick McHardy return 0; 30496518518SPatrick McHardy 30596518518SPatrick McHardy nla_put_failure: 30696518518SPatrick McHardy return -1; 30796518518SPatrick McHardy } 308aa45660cSTomasz Bursztyka EXPORT_SYMBOL_GPL(nft_meta_get_dump); 30996518518SPatrick McHardy 310aa45660cSTomasz Bursztyka int nft_meta_set_dump(struct sk_buff *skb, 311e035b77aSArturo Borrero Gonzalez const struct nft_expr *expr) 312e035b77aSArturo Borrero Gonzalez { 313e035b77aSArturo Borrero Gonzalez const struct nft_meta *priv = nft_expr_priv(expr); 314e035b77aSArturo Borrero Gonzalez 315e035b77aSArturo Borrero Gonzalez if (nla_put_be32(skb, NFTA_META_KEY, htonl(priv->key))) 316e035b77aSArturo Borrero Gonzalez goto nla_put_failure; 317e035b77aSArturo Borrero Gonzalez if (nla_put_be32(skb, NFTA_META_SREG, htonl(priv->sreg))) 318e035b77aSArturo Borrero Gonzalez goto nla_put_failure; 319e035b77aSArturo Borrero Gonzalez 320e035b77aSArturo Borrero Gonzalez return 0; 321e035b77aSArturo Borrero Gonzalez 322e035b77aSArturo Borrero Gonzalez nla_put_failure: 323e035b77aSArturo Borrero Gonzalez return -1; 324e035b77aSArturo Borrero Gonzalez } 325aa45660cSTomasz Bursztyka EXPORT_SYMBOL_GPL(nft_meta_set_dump); 326e035b77aSArturo Borrero Gonzalez 327ef1f7df9SPatrick McHardy static struct nft_expr_type nft_meta_type; 328e035b77aSArturo Borrero Gonzalez static const struct nft_expr_ops nft_meta_get_ops = { 329ef1f7df9SPatrick McHardy .type = &nft_meta_type, 33096518518SPatrick McHardy .size = NFT_EXPR_SIZE(sizeof(struct nft_meta)), 331e035b77aSArturo Borrero Gonzalez .eval = nft_meta_get_eval, 332d2caa696SPatrick McHardy .init = nft_meta_get_init, 333e035b77aSArturo Borrero Gonzalez .dump = nft_meta_get_dump, 334ef1f7df9SPatrick McHardy }; 335ef1f7df9SPatrick McHardy 336e035b77aSArturo Borrero Gonzalez static const struct nft_expr_ops nft_meta_set_ops = { 337e035b77aSArturo Borrero Gonzalez .type = &nft_meta_type, 338e035b77aSArturo Borrero Gonzalez .size = NFT_EXPR_SIZE(sizeof(struct nft_meta)), 339e035b77aSArturo Borrero Gonzalez .eval = nft_meta_set_eval, 340d2caa696SPatrick McHardy .init = nft_meta_set_init, 341e035b77aSArturo Borrero Gonzalez .dump = nft_meta_set_dump, 342e035b77aSArturo Borrero Gonzalez }; 343e035b77aSArturo Borrero Gonzalez 344e035b77aSArturo Borrero Gonzalez static const struct nft_expr_ops * 345e035b77aSArturo Borrero Gonzalez nft_meta_select_ops(const struct nft_ctx *ctx, 346e035b77aSArturo Borrero Gonzalez const struct nlattr * const tb[]) 347e035b77aSArturo Borrero Gonzalez { 348e035b77aSArturo Borrero Gonzalez if (tb[NFTA_META_KEY] == NULL) 349e035b77aSArturo Borrero Gonzalez return ERR_PTR(-EINVAL); 350e035b77aSArturo Borrero Gonzalez 351e035b77aSArturo Borrero Gonzalez if (tb[NFTA_META_DREG] && tb[NFTA_META_SREG]) 352e035b77aSArturo Borrero Gonzalez return ERR_PTR(-EINVAL); 353e035b77aSArturo Borrero Gonzalez 354e035b77aSArturo Borrero Gonzalez if (tb[NFTA_META_DREG]) 355e035b77aSArturo Borrero Gonzalez return &nft_meta_get_ops; 356e035b77aSArturo Borrero Gonzalez 357e035b77aSArturo Borrero Gonzalez if (tb[NFTA_META_SREG]) 358e035b77aSArturo Borrero Gonzalez return &nft_meta_set_ops; 359e035b77aSArturo Borrero Gonzalez 360e035b77aSArturo Borrero Gonzalez return ERR_PTR(-EINVAL); 361e035b77aSArturo Borrero Gonzalez } 362e035b77aSArturo Borrero Gonzalez 363ef1f7df9SPatrick McHardy static struct nft_expr_type nft_meta_type __read_mostly = { 364ef1f7df9SPatrick McHardy .name = "meta", 365e035b77aSArturo Borrero Gonzalez .select_ops = &nft_meta_select_ops, 36696518518SPatrick McHardy .policy = nft_meta_policy, 36796518518SPatrick McHardy .maxattr = NFTA_META_MAX, 368ef1f7df9SPatrick McHardy .owner = THIS_MODULE, 36996518518SPatrick McHardy }; 37096518518SPatrick McHardy 37196518518SPatrick McHardy static int __init nft_meta_module_init(void) 37296518518SPatrick McHardy { 373ef1f7df9SPatrick McHardy return nft_register_expr(&nft_meta_type); 37496518518SPatrick McHardy } 37596518518SPatrick McHardy 37696518518SPatrick McHardy static void __exit nft_meta_module_exit(void) 37796518518SPatrick McHardy { 378ef1f7df9SPatrick McHardy nft_unregister_expr(&nft_meta_type); 37996518518SPatrick McHardy } 38096518518SPatrick McHardy 38196518518SPatrick McHardy module_init(nft_meta_module_init); 38296518518SPatrick McHardy module_exit(nft_meta_module_exit); 38396518518SPatrick McHardy 38496518518SPatrick McHardy MODULE_LICENSE("GPL"); 38596518518SPatrick McHardy MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); 38696518518SPatrick McHardy MODULE_ALIAS_NFT_EXPR("meta"); 387