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 = ®s->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"); 154
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.