1 /* 2 * lwtunnel Infrastructure for light weight tunnels like mpls 3 * 4 * Authors: Roopa Prabhu, <roopa@cumulusnetworks.com> 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * as published by the Free Software Foundation; either version 9 * 2 of the License, or (at your option) any later version. 10 * 11 */ 12 13 #include <linux/capability.h> 14 #include <linux/module.h> 15 #include <linux/types.h> 16 #include <linux/kernel.h> 17 #include <linux/slab.h> 18 #include <linux/uaccess.h> 19 #include <linux/skbuff.h> 20 #include <linux/netdevice.h> 21 #include <linux/lwtunnel.h> 22 #include <linux/in.h> 23 #include <linux/init.h> 24 #include <linux/err.h> 25 26 #include <net/lwtunnel.h> 27 #include <net/rtnetlink.h> 28 #include <net/ip6_fib.h> 29 30 #ifdef CONFIG_MODULES 31 32 static const char *lwtunnel_encap_str(enum lwtunnel_encap_types encap_type) 33 { 34 /* Only lwt encaps implemented without using an interface for 35 * the encap need to return a string here. 36 */ 37 switch (encap_type) { 38 case LWTUNNEL_ENCAP_MPLS: 39 return "MPLS"; 40 case LWTUNNEL_ENCAP_ILA: 41 return "ILA"; 42 case LWTUNNEL_ENCAP_SEG6: 43 return "SEG6"; 44 case LWTUNNEL_ENCAP_IP6: 45 case LWTUNNEL_ENCAP_IP: 46 case LWTUNNEL_ENCAP_NONE: 47 case __LWTUNNEL_ENCAP_MAX: 48 /* should not have got here */ 49 WARN_ON(1); 50 break; 51 } 52 return NULL; 53 } 54 55 #endif /* CONFIG_MODULES */ 56 57 struct lwtunnel_state *lwtunnel_state_alloc(int encap_len) 58 { 59 struct lwtunnel_state *lws; 60 61 lws = kzalloc(sizeof(*lws) + encap_len, GFP_ATOMIC); 62 63 return lws; 64 } 65 EXPORT_SYMBOL(lwtunnel_state_alloc); 66 67 static const struct lwtunnel_encap_ops __rcu * 68 lwtun_encaps[LWTUNNEL_ENCAP_MAX + 1] __read_mostly; 69 70 int lwtunnel_encap_add_ops(const struct lwtunnel_encap_ops *ops, 71 unsigned int num) 72 { 73 if (num > LWTUNNEL_ENCAP_MAX) 74 return -ERANGE; 75 76 return !cmpxchg((const struct lwtunnel_encap_ops **) 77 &lwtun_encaps[num], 78 NULL, ops) ? 0 : -1; 79 } 80 EXPORT_SYMBOL(lwtunnel_encap_add_ops); 81 82 int lwtunnel_encap_del_ops(const struct lwtunnel_encap_ops *ops, 83 unsigned int encap_type) 84 { 85 int ret; 86 87 if (encap_type == LWTUNNEL_ENCAP_NONE || 88 encap_type > LWTUNNEL_ENCAP_MAX) 89 return -ERANGE; 90 91 ret = (cmpxchg((const struct lwtunnel_encap_ops **) 92 &lwtun_encaps[encap_type], 93 ops, NULL) == ops) ? 0 : -1; 94 95 synchronize_net(); 96 97 return ret; 98 } 99 EXPORT_SYMBOL(lwtunnel_encap_del_ops); 100 101 int lwtunnel_build_state(struct net_device *dev, u16 encap_type, 102 struct nlattr *encap, unsigned int family, 103 const void *cfg, struct lwtunnel_state **lws) 104 { 105 const struct lwtunnel_encap_ops *ops; 106 int ret = -EINVAL; 107 108 if (encap_type == LWTUNNEL_ENCAP_NONE || 109 encap_type > LWTUNNEL_ENCAP_MAX) 110 return ret; 111 112 ret = -EOPNOTSUPP; 113 rcu_read_lock(); 114 ops = rcu_dereference(lwtun_encaps[encap_type]); 115 #ifdef CONFIG_MODULES 116 if (!ops) { 117 const char *encap_type_str = lwtunnel_encap_str(encap_type); 118 119 if (encap_type_str) { 120 rcu_read_unlock(); 121 request_module("rtnl-lwt-%s", encap_type_str); 122 rcu_read_lock(); 123 ops = rcu_dereference(lwtun_encaps[encap_type]); 124 } 125 } 126 #endif 127 if (likely(ops && ops->build_state)) 128 ret = ops->build_state(dev, encap, family, cfg, lws); 129 rcu_read_unlock(); 130 131 return ret; 132 } 133 EXPORT_SYMBOL(lwtunnel_build_state); 134 135 void lwtstate_free(struct lwtunnel_state *lws) 136 { 137 const struct lwtunnel_encap_ops *ops = lwtun_encaps[lws->type]; 138 139 if (ops->destroy_state) { 140 ops->destroy_state(lws); 141 kfree_rcu(lws, rcu); 142 } else { 143 kfree(lws); 144 } 145 } 146 EXPORT_SYMBOL(lwtstate_free); 147 148 int lwtunnel_fill_encap(struct sk_buff *skb, struct lwtunnel_state *lwtstate) 149 { 150 const struct lwtunnel_encap_ops *ops; 151 struct nlattr *nest; 152 int ret = -EINVAL; 153 154 if (!lwtstate) 155 return 0; 156 157 if (lwtstate->type == LWTUNNEL_ENCAP_NONE || 158 lwtstate->type > LWTUNNEL_ENCAP_MAX) 159 return 0; 160 161 ret = -EOPNOTSUPP; 162 nest = nla_nest_start(skb, RTA_ENCAP); 163 rcu_read_lock(); 164 ops = rcu_dereference(lwtun_encaps[lwtstate->type]); 165 if (likely(ops && ops->fill_encap)) 166 ret = ops->fill_encap(skb, lwtstate); 167 rcu_read_unlock(); 168 169 if (ret) 170 goto nla_put_failure; 171 nla_nest_end(skb, nest); 172 ret = nla_put_u16(skb, RTA_ENCAP_TYPE, lwtstate->type); 173 if (ret) 174 goto nla_put_failure; 175 176 return 0; 177 178 nla_put_failure: 179 nla_nest_cancel(skb, nest); 180 181 return (ret == -EOPNOTSUPP ? 0 : ret); 182 } 183 EXPORT_SYMBOL(lwtunnel_fill_encap); 184 185 int lwtunnel_get_encap_size(struct lwtunnel_state *lwtstate) 186 { 187 const struct lwtunnel_encap_ops *ops; 188 int ret = 0; 189 190 if (!lwtstate) 191 return 0; 192 193 if (lwtstate->type == LWTUNNEL_ENCAP_NONE || 194 lwtstate->type > LWTUNNEL_ENCAP_MAX) 195 return 0; 196 197 rcu_read_lock(); 198 ops = rcu_dereference(lwtun_encaps[lwtstate->type]); 199 if (likely(ops && ops->get_encap_size)) 200 ret = nla_total_size(ops->get_encap_size(lwtstate)); 201 rcu_read_unlock(); 202 203 return ret; 204 } 205 EXPORT_SYMBOL(lwtunnel_get_encap_size); 206 207 int lwtunnel_cmp_encap(struct lwtunnel_state *a, struct lwtunnel_state *b) 208 { 209 const struct lwtunnel_encap_ops *ops; 210 int ret = 0; 211 212 if (!a && !b) 213 return 0; 214 215 if (!a || !b) 216 return 1; 217 218 if (a->type != b->type) 219 return 1; 220 221 if (a->type == LWTUNNEL_ENCAP_NONE || 222 a->type > LWTUNNEL_ENCAP_MAX) 223 return 0; 224 225 rcu_read_lock(); 226 ops = rcu_dereference(lwtun_encaps[a->type]); 227 if (likely(ops && ops->cmp_encap)) 228 ret = ops->cmp_encap(a, b); 229 rcu_read_unlock(); 230 231 return ret; 232 } 233 EXPORT_SYMBOL(lwtunnel_cmp_encap); 234 235 int lwtunnel_output(struct net *net, struct sock *sk, struct sk_buff *skb) 236 { 237 struct dst_entry *dst = skb_dst(skb); 238 const struct lwtunnel_encap_ops *ops; 239 struct lwtunnel_state *lwtstate; 240 int ret = -EINVAL; 241 242 if (!dst) 243 goto drop; 244 lwtstate = dst->lwtstate; 245 246 if (lwtstate->type == LWTUNNEL_ENCAP_NONE || 247 lwtstate->type > LWTUNNEL_ENCAP_MAX) 248 return 0; 249 250 ret = -EOPNOTSUPP; 251 rcu_read_lock(); 252 ops = rcu_dereference(lwtun_encaps[lwtstate->type]); 253 if (likely(ops && ops->output)) 254 ret = ops->output(net, sk, skb); 255 rcu_read_unlock(); 256 257 if (ret == -EOPNOTSUPP) 258 goto drop; 259 260 return ret; 261 262 drop: 263 kfree_skb(skb); 264 265 return ret; 266 } 267 EXPORT_SYMBOL(lwtunnel_output); 268 269 int lwtunnel_xmit(struct sk_buff *skb) 270 { 271 struct dst_entry *dst = skb_dst(skb); 272 const struct lwtunnel_encap_ops *ops; 273 struct lwtunnel_state *lwtstate; 274 int ret = -EINVAL; 275 276 if (!dst) 277 goto drop; 278 279 lwtstate = dst->lwtstate; 280 281 if (lwtstate->type == LWTUNNEL_ENCAP_NONE || 282 lwtstate->type > LWTUNNEL_ENCAP_MAX) 283 return 0; 284 285 ret = -EOPNOTSUPP; 286 rcu_read_lock(); 287 ops = rcu_dereference(lwtun_encaps[lwtstate->type]); 288 if (likely(ops && ops->xmit)) 289 ret = ops->xmit(skb); 290 rcu_read_unlock(); 291 292 if (ret == -EOPNOTSUPP) 293 goto drop; 294 295 return ret; 296 297 drop: 298 kfree_skb(skb); 299 300 return ret; 301 } 302 EXPORT_SYMBOL(lwtunnel_xmit); 303 304 int lwtunnel_input(struct sk_buff *skb) 305 { 306 struct dst_entry *dst = skb_dst(skb); 307 const struct lwtunnel_encap_ops *ops; 308 struct lwtunnel_state *lwtstate; 309 int ret = -EINVAL; 310 311 if (!dst) 312 goto drop; 313 lwtstate = dst->lwtstate; 314 315 if (lwtstate->type == LWTUNNEL_ENCAP_NONE || 316 lwtstate->type > LWTUNNEL_ENCAP_MAX) 317 return 0; 318 319 ret = -EOPNOTSUPP; 320 rcu_read_lock(); 321 ops = rcu_dereference(lwtun_encaps[lwtstate->type]); 322 if (likely(ops && ops->input)) 323 ret = ops->input(skb); 324 rcu_read_unlock(); 325 326 if (ret == -EOPNOTSUPP) 327 goto drop; 328 329 return ret; 330 331 drop: 332 kfree_skb(skb); 333 334 return ret; 335 } 336 EXPORT_SYMBOL(lwtunnel_input); 337