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_IP6: 43 case LWTUNNEL_ENCAP_IP: 44 case LWTUNNEL_ENCAP_NONE: 45 case __LWTUNNEL_ENCAP_MAX: 46 /* should not have got here */ 47 WARN_ON(1); 48 break; 49 } 50 return NULL; 51 } 52 53 #endif /* CONFIG_MODULES */ 54 55 struct lwtunnel_state *lwtunnel_state_alloc(int encap_len) 56 { 57 struct lwtunnel_state *lws; 58 59 lws = kzalloc(sizeof(*lws) + encap_len, GFP_ATOMIC); 60 61 return lws; 62 } 63 EXPORT_SYMBOL(lwtunnel_state_alloc); 64 65 static const struct lwtunnel_encap_ops __rcu * 66 lwtun_encaps[LWTUNNEL_ENCAP_MAX + 1] __read_mostly; 67 68 int lwtunnel_encap_add_ops(const struct lwtunnel_encap_ops *ops, 69 unsigned int num) 70 { 71 if (num > LWTUNNEL_ENCAP_MAX) 72 return -ERANGE; 73 74 return !cmpxchg((const struct lwtunnel_encap_ops **) 75 &lwtun_encaps[num], 76 NULL, ops) ? 0 : -1; 77 } 78 EXPORT_SYMBOL(lwtunnel_encap_add_ops); 79 80 int lwtunnel_encap_del_ops(const struct lwtunnel_encap_ops *ops, 81 unsigned int encap_type) 82 { 83 int ret; 84 85 if (encap_type == LWTUNNEL_ENCAP_NONE || 86 encap_type > LWTUNNEL_ENCAP_MAX) 87 return -ERANGE; 88 89 ret = (cmpxchg((const struct lwtunnel_encap_ops **) 90 &lwtun_encaps[encap_type], 91 ops, NULL) == ops) ? 0 : -1; 92 93 synchronize_net(); 94 95 return ret; 96 } 97 EXPORT_SYMBOL(lwtunnel_encap_del_ops); 98 99 int lwtunnel_build_state(struct net_device *dev, u16 encap_type, 100 struct nlattr *encap, unsigned int family, 101 const void *cfg, struct lwtunnel_state **lws) 102 { 103 const struct lwtunnel_encap_ops *ops; 104 int ret = -EINVAL; 105 106 if (encap_type == LWTUNNEL_ENCAP_NONE || 107 encap_type > LWTUNNEL_ENCAP_MAX) 108 return ret; 109 110 ret = -EOPNOTSUPP; 111 rcu_read_lock(); 112 ops = rcu_dereference(lwtun_encaps[encap_type]); 113 #ifdef CONFIG_MODULES 114 if (!ops) { 115 const char *encap_type_str = lwtunnel_encap_str(encap_type); 116 117 if (encap_type_str) { 118 rcu_read_unlock(); 119 request_module("rtnl-lwt-%s", encap_type_str); 120 rcu_read_lock(); 121 ops = rcu_dereference(lwtun_encaps[encap_type]); 122 } 123 } 124 #endif 125 if (likely(ops && ops->build_state)) 126 ret = ops->build_state(dev, encap, family, cfg, lws); 127 rcu_read_unlock(); 128 129 return ret; 130 } 131 EXPORT_SYMBOL(lwtunnel_build_state); 132 133 int lwtunnel_fill_encap(struct sk_buff *skb, struct lwtunnel_state *lwtstate) 134 { 135 const struct lwtunnel_encap_ops *ops; 136 struct nlattr *nest; 137 int ret = -EINVAL; 138 139 if (!lwtstate) 140 return 0; 141 142 if (lwtstate->type == LWTUNNEL_ENCAP_NONE || 143 lwtstate->type > LWTUNNEL_ENCAP_MAX) 144 return 0; 145 146 ret = -EOPNOTSUPP; 147 nest = nla_nest_start(skb, RTA_ENCAP); 148 rcu_read_lock(); 149 ops = rcu_dereference(lwtun_encaps[lwtstate->type]); 150 if (likely(ops && ops->fill_encap)) 151 ret = ops->fill_encap(skb, lwtstate); 152 rcu_read_unlock(); 153 154 if (ret) 155 goto nla_put_failure; 156 nla_nest_end(skb, nest); 157 ret = nla_put_u16(skb, RTA_ENCAP_TYPE, lwtstate->type); 158 if (ret) 159 goto nla_put_failure; 160 161 return 0; 162 163 nla_put_failure: 164 nla_nest_cancel(skb, nest); 165 166 return (ret == -EOPNOTSUPP ? 0 : ret); 167 } 168 EXPORT_SYMBOL(lwtunnel_fill_encap); 169 170 int lwtunnel_get_encap_size(struct lwtunnel_state *lwtstate) 171 { 172 const struct lwtunnel_encap_ops *ops; 173 int ret = 0; 174 175 if (!lwtstate) 176 return 0; 177 178 if (lwtstate->type == LWTUNNEL_ENCAP_NONE || 179 lwtstate->type > LWTUNNEL_ENCAP_MAX) 180 return 0; 181 182 rcu_read_lock(); 183 ops = rcu_dereference(lwtun_encaps[lwtstate->type]); 184 if (likely(ops && ops->get_encap_size)) 185 ret = nla_total_size(ops->get_encap_size(lwtstate)); 186 rcu_read_unlock(); 187 188 return ret; 189 } 190 EXPORT_SYMBOL(lwtunnel_get_encap_size); 191 192 int lwtunnel_cmp_encap(struct lwtunnel_state *a, struct lwtunnel_state *b) 193 { 194 const struct lwtunnel_encap_ops *ops; 195 int ret = 0; 196 197 if (!a && !b) 198 return 0; 199 200 if (!a || !b) 201 return 1; 202 203 if (a->type != b->type) 204 return 1; 205 206 if (a->type == LWTUNNEL_ENCAP_NONE || 207 a->type > LWTUNNEL_ENCAP_MAX) 208 return 0; 209 210 rcu_read_lock(); 211 ops = rcu_dereference(lwtun_encaps[a->type]); 212 if (likely(ops && ops->cmp_encap)) 213 ret = ops->cmp_encap(a, b); 214 rcu_read_unlock(); 215 216 return ret; 217 } 218 EXPORT_SYMBOL(lwtunnel_cmp_encap); 219 220 int lwtunnel_output(struct net *net, struct sock *sk, struct sk_buff *skb) 221 { 222 struct dst_entry *dst = skb_dst(skb); 223 const struct lwtunnel_encap_ops *ops; 224 struct lwtunnel_state *lwtstate; 225 int ret = -EINVAL; 226 227 if (!dst) 228 goto drop; 229 lwtstate = dst->lwtstate; 230 231 if (lwtstate->type == LWTUNNEL_ENCAP_NONE || 232 lwtstate->type > LWTUNNEL_ENCAP_MAX) 233 return 0; 234 235 ret = -EOPNOTSUPP; 236 rcu_read_lock(); 237 ops = rcu_dereference(lwtun_encaps[lwtstate->type]); 238 if (likely(ops && ops->output)) 239 ret = ops->output(net, sk, skb); 240 rcu_read_unlock(); 241 242 if (ret == -EOPNOTSUPP) 243 goto drop; 244 245 return ret; 246 247 drop: 248 kfree_skb(skb); 249 250 return ret; 251 } 252 EXPORT_SYMBOL(lwtunnel_output); 253 254 int lwtunnel_input(struct sk_buff *skb) 255 { 256 struct dst_entry *dst = skb_dst(skb); 257 const struct lwtunnel_encap_ops *ops; 258 struct lwtunnel_state *lwtstate; 259 int ret = -EINVAL; 260 261 if (!dst) 262 goto drop; 263 lwtstate = dst->lwtstate; 264 265 if (lwtstate->type == LWTUNNEL_ENCAP_NONE || 266 lwtstate->type > LWTUNNEL_ENCAP_MAX) 267 return 0; 268 269 ret = -EOPNOTSUPP; 270 rcu_read_lock(); 271 ops = rcu_dereference(lwtun_encaps[lwtstate->type]); 272 if (likely(ops && ops->input)) 273 ret = ops->input(skb); 274 rcu_read_unlock(); 275 276 if (ret == -EOPNOTSUPP) 277 goto drop; 278 279 return ret; 280 281 drop: 282 kfree_skb(skb); 283 284 return ret; 285 } 286 EXPORT_SYMBOL(lwtunnel_input); 287