]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - net/netfilter/nft_rt.c
mm, shmem: fix handling /sys/kernel/mm/transparent_hugepage/shmem_enabled
[karo-tx-linux.git] / net / netfilter / nft_rt.c
1 /*
2  * Copyright (c) 2016 Anders K. Pedersen <akp@cohaesio.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation.
7  */
8
9 #include <linux/kernel.h>
10 #include <linux/init.h>
11 #include <linux/module.h>
12 #include <linux/netlink.h>
13 #include <linux/netfilter.h>
14 #include <linux/netfilter/nf_tables.h>
15 #include <net/dst.h>
16 #include <net/ip6_route.h>
17 #include <net/route.h>
18 #include <net/netfilter/nf_tables.h>
19 #include <net/netfilter/nf_tables_core.h>
20
21 struct nft_rt {
22         enum nft_rt_keys        key:8;
23         enum nft_registers      dreg:8;
24 };
25
26 static void nft_rt_get_eval(const struct nft_expr *expr,
27                             struct nft_regs *regs,
28                             const struct nft_pktinfo *pkt)
29 {
30         const struct nft_rt *priv = nft_expr_priv(expr);
31         const struct sk_buff *skb = pkt->skb;
32         u32 *dest = &regs->data[priv->dreg];
33         const struct dst_entry *dst;
34
35         dst = skb_dst(skb);
36         if (!dst)
37                 goto err;
38
39         switch (priv->key) {
40 #ifdef CONFIG_IP_ROUTE_CLASSID
41         case NFT_RT_CLASSID:
42                 *dest = dst->tclassid;
43                 break;
44 #endif
45         case NFT_RT_NEXTHOP4:
46                 if (nft_pf(pkt) != NFPROTO_IPV4)
47                         goto err;
48
49                 *dest = rt_nexthop((const struct rtable *)dst,
50                                    ip_hdr(skb)->daddr);
51                 break;
52         case NFT_RT_NEXTHOP6:
53                 if (nft_pf(pkt) != NFPROTO_IPV6)
54                         goto err;
55
56                 memcpy(dest, rt6_nexthop((struct rt6_info *)dst,
57                                          &ipv6_hdr(skb)->daddr),
58                        sizeof(struct in6_addr));
59                 break;
60         default:
61                 WARN_ON(1);
62                 goto err;
63         }
64         return;
65
66 err:
67         regs->verdict.code = NFT_BREAK;
68 }
69
70 const struct nla_policy nft_rt_policy[NFTA_RT_MAX + 1] = {
71         [NFTA_RT_DREG]          = { .type = NLA_U32 },
72         [NFTA_RT_KEY]           = { .type = NLA_U32 },
73 };
74
75 static int nft_rt_get_init(const struct nft_ctx *ctx,
76                            const struct nft_expr *expr,
77                            const struct nlattr * const tb[])
78 {
79         struct nft_rt *priv = nft_expr_priv(expr);
80         unsigned int len;
81
82         if (tb[NFTA_RT_KEY] == NULL ||
83             tb[NFTA_RT_DREG] == NULL)
84                 return -EINVAL;
85
86         priv->key = ntohl(nla_get_be32(tb[NFTA_RT_KEY]));
87         switch (priv->key) {
88 #ifdef CONFIG_IP_ROUTE_CLASSID
89         case NFT_RT_CLASSID:
90 #endif
91         case NFT_RT_NEXTHOP4:
92                 len = sizeof(u32);
93                 break;
94         case NFT_RT_NEXTHOP6:
95                 len = sizeof(struct in6_addr);
96                 break;
97         default:
98                 return -EOPNOTSUPP;
99         }
100
101         priv->dreg = nft_parse_register(tb[NFTA_RT_DREG]);
102         return nft_validate_register_store(ctx, priv->dreg, NULL,
103                                            NFT_DATA_VALUE, len);
104 }
105
106 static int nft_rt_get_dump(struct sk_buff *skb,
107                            const struct nft_expr *expr)
108 {
109         const struct nft_rt *priv = nft_expr_priv(expr);
110
111         if (nla_put_be32(skb, NFTA_RT_KEY, htonl(priv->key)))
112                 goto nla_put_failure;
113         if (nft_dump_register(skb, NFTA_RT_DREG, priv->dreg))
114                 goto nla_put_failure;
115         return 0;
116
117 nla_put_failure:
118         return -1;
119 }
120
121 static struct nft_expr_type nft_rt_type;
122 static const struct nft_expr_ops nft_rt_get_ops = {
123         .type           = &nft_rt_type,
124         .size           = NFT_EXPR_SIZE(sizeof(struct nft_rt)),
125         .eval           = nft_rt_get_eval,
126         .init           = nft_rt_get_init,
127         .dump           = nft_rt_get_dump,
128 };
129
130 static struct nft_expr_type nft_rt_type __read_mostly = {
131         .name           = "rt",
132         .ops            = &nft_rt_get_ops,
133         .policy         = nft_rt_policy,
134         .maxattr        = NFTA_RT_MAX,
135         .owner          = THIS_MODULE,
136 };
137
138 static int __init nft_rt_module_init(void)
139 {
140         return nft_register_expr(&nft_rt_type);
141 }
142
143 static void __exit nft_rt_module_exit(void)
144 {
145         nft_unregister_expr(&nft_rt_type);
146 }
147
148 module_init(nft_rt_module_init);
149 module_exit(nft_rt_module_exit);
150
151 MODULE_LICENSE("GPL");
152 MODULE_AUTHOR("Anders K. Pedersen <akp@cohaesio.com>");
153 MODULE_ALIAS_NFT_EXPR("rt");