1 // SPDX-License-Identifier: GPL-2.0 2 #include <linux/errno.h> 3 #include <linux/ip.h> 4 #include <linux/kernel.h> 5 #include <linux/module.h> 6 #include <linux/skbuff.h> 7 #include <linux/socket.h> 8 #include <linux/types.h> 9 #include <net/checksum.h> 10 #include <net/dst_cache.h> 11 #include <net/ip.h> 12 #include <net/ip6_fib.h> 13 #include <net/ip6_route.h> 14 #include <net/lwtunnel.h> 15 #include <net/protocol.h> 16 #include <uapi/linux/ila.h> 17 #include "ila.h" 18 19 struct ila_lwt { 20 struct ila_params p; 21 struct dst_cache dst_cache; 22 u32 connected : 1; 23 }; 24 25 static inline struct ila_lwt *ila_lwt_lwtunnel( 26 struct lwtunnel_state *lwt) 27 { 28 return (struct ila_lwt *)lwt->data; 29 } 30 31 static inline struct ila_params *ila_params_lwtunnel( 32 struct lwtunnel_state *lwt) 33 { 34 return &ila_lwt_lwtunnel(lwt)->p; 35 } 36 37 static int ila_output(struct net *net, struct sock *sk, struct sk_buff *skb) 38 { 39 struct dst_entry *orig_dst = skb_dst(skb); 40 struct rt6_info *rt = (struct rt6_info *)orig_dst; 41 struct ila_lwt *ilwt = ila_lwt_lwtunnel(orig_dst->lwtstate); 42 struct dst_entry *dst; 43 int err = -EINVAL; 44 45 if (skb->protocol != htons(ETH_P_IPV6)) 46 goto drop; 47 48 ila_update_ipv6_locator(skb, ila_params_lwtunnel(orig_dst->lwtstate), 49 true); 50 51 if (rt->rt6i_flags & (RTF_GATEWAY | RTF_CACHE)) { 52 /* Already have a next hop address in route, no need for 53 * dest cache route. 54 */ 55 return orig_dst->lwtstate->orig_output(net, sk, skb); 56 } 57 58 dst = dst_cache_get(&ilwt->dst_cache); 59 if (unlikely(!dst)) { 60 struct ipv6hdr *ip6h = ipv6_hdr(skb); 61 struct flowi6 fl6; 62 63 /* Lookup a route for the new destination. Take into 64 * account that the base route may already have a gateway. 65 */ 66 67 memset(&fl6, 0, sizeof(fl6)); 68 fl6.flowi6_oif = orig_dst->dev->ifindex; 69 fl6.flowi6_iif = LOOPBACK_IFINDEX; 70 fl6.daddr = *rt6_nexthop((struct rt6_info *)orig_dst, 71 &ip6h->daddr); 72 73 dst = ip6_route_output(net, NULL, &fl6); 74 if (dst->error) { 75 err = -EHOSTUNREACH; 76 dst_release(dst); 77 goto drop; 78 } 79 80 dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), NULL, 0); 81 if (IS_ERR(dst)) { 82 err = PTR_ERR(dst); 83 goto drop; 84 } 85 86 if (ilwt->connected) 87 dst_cache_set_ip6(&ilwt->dst_cache, dst, &fl6.saddr); 88 } 89 90 skb_dst_set(skb, dst); 91 return dst_output(net, sk, skb); 92 93 drop: 94 kfree_skb(skb); 95 return err; 96 } 97 98 static int ila_input(struct sk_buff *skb) 99 { 100 struct dst_entry *dst = skb_dst(skb); 101 102 if (skb->protocol != htons(ETH_P_IPV6)) 103 goto drop; 104 105 ila_update_ipv6_locator(skb, ila_params_lwtunnel(dst->lwtstate), false); 106 107 return dst->lwtstate->orig_input(skb); 108 109 drop: 110 kfree_skb(skb); 111 return -EINVAL; 112 } 113 114 static const struct nla_policy ila_nl_policy[ILA_ATTR_MAX + 1] = { 115 [ILA_ATTR_LOCATOR] = { .type = NLA_U64, }, 116 [ILA_ATTR_CSUM_MODE] = { .type = NLA_U8, }, 117 }; 118 119 static int ila_build_state(struct nlattr *nla, 120 unsigned int family, const void *cfg, 121 struct lwtunnel_state **ts, 122 struct netlink_ext_ack *extack) 123 { 124 struct ila_lwt *ilwt; 125 struct ila_params *p; 126 struct nlattr *tb[ILA_ATTR_MAX + 1]; 127 struct lwtunnel_state *newts; 128 const struct fib6_config *cfg6 = cfg; 129 struct ila_addr *iaddr; 130 int ret; 131 132 if (family != AF_INET6) 133 return -EINVAL; 134 135 if (cfg6->fc_dst_len < 8 * sizeof(struct ila_locator) + 3) { 136 /* Need to have full locator and at least type field 137 * included in destination 138 */ 139 return -EINVAL; 140 } 141 142 iaddr = (struct ila_addr *)&cfg6->fc_dst; 143 144 if (!ila_addr_is_ila(iaddr) || ila_csum_neutral_set(iaddr->ident)) { 145 /* Don't allow translation for a non-ILA address or checksum 146 * neutral flag to be set. 147 */ 148 return -EINVAL; 149 } 150 151 ret = nla_parse_nested(tb, ILA_ATTR_MAX, nla, ila_nl_policy, extack); 152 if (ret < 0) 153 return ret; 154 155 if (!tb[ILA_ATTR_LOCATOR]) 156 return -EINVAL; 157 158 newts = lwtunnel_state_alloc(sizeof(*ilwt)); 159 if (!newts) 160 return -ENOMEM; 161 162 ilwt = ila_lwt_lwtunnel(newts); 163 ret = dst_cache_init(&ilwt->dst_cache, GFP_ATOMIC); 164 if (ret) { 165 kfree(newts); 166 return ret; 167 } 168 169 p = ila_params_lwtunnel(newts); 170 171 p->locator.v64 = (__force __be64)nla_get_u64(tb[ILA_ATTR_LOCATOR]); 172 173 /* Precompute checksum difference for translation since we 174 * know both the old locator and the new one. 175 */ 176 p->locator_match = iaddr->loc; 177 p->csum_diff = compute_csum_diff8( 178 (__be32 *)&p->locator_match, (__be32 *)&p->locator); 179 180 if (tb[ILA_ATTR_CSUM_MODE]) 181 p->csum_mode = nla_get_u8(tb[ILA_ATTR_CSUM_MODE]); 182 183 ila_init_saved_csum(p); 184 185 newts->type = LWTUNNEL_ENCAP_ILA; 186 newts->flags |= LWTUNNEL_STATE_OUTPUT_REDIRECT | 187 LWTUNNEL_STATE_INPUT_REDIRECT; 188 189 if (cfg6->fc_dst_len == 8 * sizeof(struct in6_addr)) 190 ilwt->connected = 1; 191 192 *ts = newts; 193 194 return 0; 195 } 196 197 static void ila_destroy_state(struct lwtunnel_state *lwt) 198 { 199 dst_cache_destroy(&ila_lwt_lwtunnel(lwt)->dst_cache); 200 } 201 202 static int ila_fill_encap_info(struct sk_buff *skb, 203 struct lwtunnel_state *lwtstate) 204 { 205 struct ila_params *p = ila_params_lwtunnel(lwtstate); 206 207 if (nla_put_u64_64bit(skb, ILA_ATTR_LOCATOR, (__force u64)p->locator.v64, 208 ILA_ATTR_PAD)) 209 goto nla_put_failure; 210 if (nla_put_u8(skb, ILA_ATTR_CSUM_MODE, (__force u8)p->csum_mode)) 211 goto nla_put_failure; 212 213 return 0; 214 215 nla_put_failure: 216 return -EMSGSIZE; 217 } 218 219 static int ila_encap_nlsize(struct lwtunnel_state *lwtstate) 220 { 221 return nla_total_size_64bit(sizeof(u64)) + /* ILA_ATTR_LOCATOR */ 222 nla_total_size(sizeof(u8)) + /* ILA_ATTR_CSUM_MODE */ 223 0; 224 } 225 226 static int ila_encap_cmp(struct lwtunnel_state *a, struct lwtunnel_state *b) 227 { 228 struct ila_params *a_p = ila_params_lwtunnel(a); 229 struct ila_params *b_p = ila_params_lwtunnel(b); 230 231 return (a_p->locator.v64 != b_p->locator.v64); 232 } 233 234 static const struct lwtunnel_encap_ops ila_encap_ops = { 235 .build_state = ila_build_state, 236 .destroy_state = ila_destroy_state, 237 .output = ila_output, 238 .input = ila_input, 239 .fill_encap = ila_fill_encap_info, 240 .get_encap_size = ila_encap_nlsize, 241 .cmp_encap = ila_encap_cmp, 242 .owner = THIS_MODULE, 243 }; 244 245 int ila_lwt_init(void) 246 { 247 return lwtunnel_encap_add_ops(&ila_encap_ops, LWTUNNEL_ENCAP_ILA); 248 } 249 250 void ila_lwt_fini(void) 251 { 252 lwtunnel_encap_del_ops(&ila_encap_ops, LWTUNNEL_ENCAP_ILA); 253 } 254