1 #include <linux/errno.h> 2 #include <linux/ip.h> 3 #include <linux/kernel.h> 4 #include <linux/module.h> 5 #include <linux/skbuff.h> 6 #include <linux/socket.h> 7 #include <linux/types.h> 8 #include <net/checksum.h> 9 #include <net/ip.h> 10 #include <net/ip6_fib.h> 11 #include <net/lwtunnel.h> 12 #include <net/protocol.h> 13 #include <uapi/linux/ila.h> 14 #include "ila.h" 15 16 static inline struct ila_params *ila_params_lwtunnel( 17 struct lwtunnel_state *lwstate) 18 { 19 return (struct ila_params *)lwstate->data; 20 } 21 22 static int ila_output(struct net *net, struct sock *sk, struct sk_buff *skb) 23 { 24 struct dst_entry *dst = skb_dst(skb); 25 26 if (skb->protocol != htons(ETH_P_IPV6)) 27 goto drop; 28 29 update_ipv6_locator(skb, ila_params_lwtunnel(dst->lwtstate)); 30 31 return dst->lwtstate->orig_output(net, sk, skb); 32 33 drop: 34 kfree_skb(skb); 35 return -EINVAL; 36 } 37 38 static int ila_input(struct sk_buff *skb) 39 { 40 struct dst_entry *dst = skb_dst(skb); 41 42 if (skb->protocol != htons(ETH_P_IPV6)) 43 goto drop; 44 45 update_ipv6_locator(skb, ila_params_lwtunnel(dst->lwtstate)); 46 47 return dst->lwtstate->orig_input(skb); 48 49 drop: 50 kfree_skb(skb); 51 return -EINVAL; 52 } 53 54 static struct nla_policy ila_nl_policy[ILA_ATTR_MAX + 1] = { 55 [ILA_ATTR_LOCATOR] = { .type = NLA_U64, }, 56 }; 57 58 static int ila_build_state(struct net_device *dev, struct nlattr *nla, 59 unsigned int family, const void *cfg, 60 struct lwtunnel_state **ts) 61 { 62 struct ila_params *p; 63 struct nlattr *tb[ILA_ATTR_MAX + 1]; 64 size_t encap_len = sizeof(*p); 65 struct lwtunnel_state *newts; 66 const struct fib6_config *cfg6 = cfg; 67 int ret; 68 69 if (family != AF_INET6) 70 return -EINVAL; 71 72 ret = nla_parse_nested(tb, ILA_ATTR_MAX, nla, 73 ila_nl_policy); 74 if (ret < 0) 75 return ret; 76 77 if (!tb[ILA_ATTR_LOCATOR]) 78 return -EINVAL; 79 80 newts = lwtunnel_state_alloc(encap_len); 81 if (!newts) 82 return -ENOMEM; 83 84 newts->len = encap_len; 85 p = ila_params_lwtunnel(newts); 86 87 p->locator = (__force __be64)nla_get_u64(tb[ILA_ATTR_LOCATOR]); 88 89 if (cfg6->fc_dst_len > sizeof(__be64)) { 90 /* Precompute checksum difference for translation since we 91 * know both the old locator and the new one. 92 */ 93 p->locator_match = *(__be64 *)&cfg6->fc_dst; 94 p->csum_diff = compute_csum_diff8( 95 (__be32 *)&p->locator_match, (__be32 *)&p->locator); 96 } 97 98 newts->type = LWTUNNEL_ENCAP_ILA; 99 newts->flags |= LWTUNNEL_STATE_OUTPUT_REDIRECT | 100 LWTUNNEL_STATE_INPUT_REDIRECT; 101 102 *ts = newts; 103 104 return 0; 105 } 106 107 static int ila_fill_encap_info(struct sk_buff *skb, 108 struct lwtunnel_state *lwtstate) 109 { 110 struct ila_params *p = ila_params_lwtunnel(lwtstate); 111 112 if (nla_put_u64(skb, ILA_ATTR_LOCATOR, (__force u64)p->locator)) 113 goto nla_put_failure; 114 115 return 0; 116 117 nla_put_failure: 118 return -EMSGSIZE; 119 } 120 121 static int ila_encap_nlsize(struct lwtunnel_state *lwtstate) 122 { 123 /* No encapsulation overhead */ 124 return 0; 125 } 126 127 static int ila_encap_cmp(struct lwtunnel_state *a, struct lwtunnel_state *b) 128 { 129 struct ila_params *a_p = ila_params_lwtunnel(a); 130 struct ila_params *b_p = ila_params_lwtunnel(b); 131 132 return (a_p->locator != b_p->locator); 133 } 134 135 static const struct lwtunnel_encap_ops ila_encap_ops = { 136 .build_state = ila_build_state, 137 .output = ila_output, 138 .input = ila_input, 139 .fill_encap = ila_fill_encap_info, 140 .get_encap_size = ila_encap_nlsize, 141 .cmp_encap = ila_encap_cmp, 142 }; 143 144 int ila_lwt_init(void) 145 { 146 return lwtunnel_encap_add_ops(&ila_encap_ops, LWTUNNEL_ENCAP_ILA); 147 } 148 149 void ila_lwt_fini(void) 150 { 151 lwtunnel_encap_del_ops(&ila_encap_ops, LWTUNNEL_ENCAP_ILA); 152 } 153