root/net/core/lwtunnel.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. lwtunnel_encap_str
  2. lwtunnel_state_alloc
  3. lwtunnel_encap_add_ops
  4. lwtunnel_encap_del_ops
  5. lwtunnel_build_state
  6. lwtunnel_valid_encap_type
  7. lwtunnel_valid_encap_type_attr
  8. lwtstate_free
  9. lwtunnel_fill_encap
  10. lwtunnel_get_encap_size
  11. lwtunnel_cmp_encap
  12. lwtunnel_output
  13. lwtunnel_xmit
  14. lwtunnel_input

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * lwtunnel     Infrastructure for light weight tunnels like mpls
   4  *
   5  * Authors:     Roopa Prabhu, <roopa@cumulusnetworks.com>
   6  */
   7 
   8 #include <linux/capability.h>
   9 #include <linux/module.h>
  10 #include <linux/types.h>
  11 #include <linux/kernel.h>
  12 #include <linux/slab.h>
  13 #include <linux/uaccess.h>
  14 #include <linux/skbuff.h>
  15 #include <linux/netdevice.h>
  16 #include <linux/lwtunnel.h>
  17 #include <linux/in.h>
  18 #include <linux/init.h>
  19 #include <linux/err.h>
  20 
  21 #include <net/lwtunnel.h>
  22 #include <net/rtnetlink.h>
  23 #include <net/ip6_fib.h>
  24 #include <net/rtnh.h>
  25 
  26 #ifdef CONFIG_MODULES
  27 
  28 static const char *lwtunnel_encap_str(enum lwtunnel_encap_types encap_type)
  29 {
  30         /* Only lwt encaps implemented without using an interface for
  31          * the encap need to return a string here.
  32          */
  33         switch (encap_type) {
  34         case LWTUNNEL_ENCAP_MPLS:
  35                 return "MPLS";
  36         case LWTUNNEL_ENCAP_ILA:
  37                 return "ILA";
  38         case LWTUNNEL_ENCAP_SEG6:
  39                 return "SEG6";
  40         case LWTUNNEL_ENCAP_BPF:
  41                 return "BPF";
  42         case LWTUNNEL_ENCAP_SEG6_LOCAL:
  43                 return "SEG6LOCAL";
  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_GPL(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_GPL(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_GPL(lwtunnel_encap_del_ops);
 100 
 101 int lwtunnel_build_state(u16 encap_type,
 102                          struct nlattr *encap, unsigned int family,
 103                          const void *cfg, struct lwtunnel_state **lws,
 104                          struct netlink_ext_ack *extack)
 105 {
 106         const struct lwtunnel_encap_ops *ops;
 107         bool found = false;
 108         int ret = -EINVAL;
 109 
 110         if (encap_type == LWTUNNEL_ENCAP_NONE ||
 111             encap_type > LWTUNNEL_ENCAP_MAX) {
 112                 NL_SET_ERR_MSG_ATTR(extack, encap,
 113                                     "Unknown LWT encapsulation type");
 114                 return ret;
 115         }
 116 
 117         ret = -EOPNOTSUPP;
 118         rcu_read_lock();
 119         ops = rcu_dereference(lwtun_encaps[encap_type]);
 120         if (likely(ops && ops->build_state && try_module_get(ops->owner)))
 121                 found = true;
 122         rcu_read_unlock();
 123 
 124         if (found) {
 125                 ret = ops->build_state(encap, family, cfg, lws, extack);
 126                 if (ret)
 127                         module_put(ops->owner);
 128         } else {
 129                 /* don't rely on -EOPNOTSUPP to detect match as build_state
 130                  * handlers could return it
 131                  */
 132                 NL_SET_ERR_MSG_ATTR(extack, encap,
 133                                     "LWT encapsulation type not supported");
 134         }
 135 
 136         return ret;
 137 }
 138 EXPORT_SYMBOL_GPL(lwtunnel_build_state);
 139 
 140 int lwtunnel_valid_encap_type(u16 encap_type, struct netlink_ext_ack *extack)
 141 {
 142         const struct lwtunnel_encap_ops *ops;
 143         int ret = -EINVAL;
 144 
 145         if (encap_type == LWTUNNEL_ENCAP_NONE ||
 146             encap_type > LWTUNNEL_ENCAP_MAX) {
 147                 NL_SET_ERR_MSG(extack, "Unknown lwt encapsulation type");
 148                 return ret;
 149         }
 150 
 151         rcu_read_lock();
 152         ops = rcu_dereference(lwtun_encaps[encap_type]);
 153         rcu_read_unlock();
 154 #ifdef CONFIG_MODULES
 155         if (!ops) {
 156                 const char *encap_type_str = lwtunnel_encap_str(encap_type);
 157 
 158                 if (encap_type_str) {
 159                         __rtnl_unlock();
 160                         request_module("rtnl-lwt-%s", encap_type_str);
 161                         rtnl_lock();
 162 
 163                         rcu_read_lock();
 164                         ops = rcu_dereference(lwtun_encaps[encap_type]);
 165                         rcu_read_unlock();
 166                 }
 167         }
 168 #endif
 169         ret = ops ? 0 : -EOPNOTSUPP;
 170         if (ret < 0)
 171                 NL_SET_ERR_MSG(extack, "lwt encapsulation type not supported");
 172 
 173         return ret;
 174 }
 175 EXPORT_SYMBOL_GPL(lwtunnel_valid_encap_type);
 176 
 177 int lwtunnel_valid_encap_type_attr(struct nlattr *attr, int remaining,
 178                                    struct netlink_ext_ack *extack)
 179 {
 180         struct rtnexthop *rtnh = (struct rtnexthop *)attr;
 181         struct nlattr *nla_entype;
 182         struct nlattr *attrs;
 183         u16 encap_type;
 184         int attrlen;
 185 
 186         while (rtnh_ok(rtnh, remaining)) {
 187                 attrlen = rtnh_attrlen(rtnh);
 188                 if (attrlen > 0) {
 189                         attrs = rtnh_attrs(rtnh);
 190                         nla_entype = nla_find(attrs, attrlen, RTA_ENCAP_TYPE);
 191 
 192                         if (nla_entype) {
 193                                 encap_type = nla_get_u16(nla_entype);
 194 
 195                                 if (lwtunnel_valid_encap_type(encap_type,
 196                                                               extack) != 0)
 197                                         return -EOPNOTSUPP;
 198                         }
 199                 }
 200                 rtnh = rtnh_next(rtnh, &remaining);
 201         }
 202 
 203         return 0;
 204 }
 205 EXPORT_SYMBOL_GPL(lwtunnel_valid_encap_type_attr);
 206 
 207 void lwtstate_free(struct lwtunnel_state *lws)
 208 {
 209         const struct lwtunnel_encap_ops *ops = lwtun_encaps[lws->type];
 210 
 211         if (ops->destroy_state) {
 212                 ops->destroy_state(lws);
 213                 kfree_rcu(lws, rcu);
 214         } else {
 215                 kfree(lws);
 216         }
 217         module_put(ops->owner);
 218 }
 219 EXPORT_SYMBOL_GPL(lwtstate_free);
 220 
 221 int lwtunnel_fill_encap(struct sk_buff *skb, struct lwtunnel_state *lwtstate,
 222                         int encap_attr, int encap_type_attr)
 223 {
 224         const struct lwtunnel_encap_ops *ops;
 225         struct nlattr *nest;
 226         int ret;
 227 
 228         if (!lwtstate)
 229                 return 0;
 230 
 231         if (lwtstate->type == LWTUNNEL_ENCAP_NONE ||
 232             lwtstate->type > LWTUNNEL_ENCAP_MAX)
 233                 return 0;
 234 
 235         nest = nla_nest_start_noflag(skb, encap_attr);
 236         if (!nest)
 237                 return -EMSGSIZE;
 238 
 239         ret = -EOPNOTSUPP;
 240         rcu_read_lock();
 241         ops = rcu_dereference(lwtun_encaps[lwtstate->type]);
 242         if (likely(ops && ops->fill_encap))
 243                 ret = ops->fill_encap(skb, lwtstate);
 244         rcu_read_unlock();
 245 
 246         if (ret)
 247                 goto nla_put_failure;
 248         nla_nest_end(skb, nest);
 249         ret = nla_put_u16(skb, encap_type_attr, lwtstate->type);
 250         if (ret)
 251                 goto nla_put_failure;
 252 
 253         return 0;
 254 
 255 nla_put_failure:
 256         nla_nest_cancel(skb, nest);
 257 
 258         return (ret == -EOPNOTSUPP ? 0 : ret);
 259 }
 260 EXPORT_SYMBOL_GPL(lwtunnel_fill_encap);
 261 
 262 int lwtunnel_get_encap_size(struct lwtunnel_state *lwtstate)
 263 {
 264         const struct lwtunnel_encap_ops *ops;
 265         int ret = 0;
 266 
 267         if (!lwtstate)
 268                 return 0;
 269 
 270         if (lwtstate->type == LWTUNNEL_ENCAP_NONE ||
 271             lwtstate->type > LWTUNNEL_ENCAP_MAX)
 272                 return 0;
 273 
 274         rcu_read_lock();
 275         ops = rcu_dereference(lwtun_encaps[lwtstate->type]);
 276         if (likely(ops && ops->get_encap_size))
 277                 ret = nla_total_size(ops->get_encap_size(lwtstate));
 278         rcu_read_unlock();
 279 
 280         return ret;
 281 }
 282 EXPORT_SYMBOL_GPL(lwtunnel_get_encap_size);
 283 
 284 int lwtunnel_cmp_encap(struct lwtunnel_state *a, struct lwtunnel_state *b)
 285 {
 286         const struct lwtunnel_encap_ops *ops;
 287         int ret = 0;
 288 
 289         if (!a && !b)
 290                 return 0;
 291 
 292         if (!a || !b)
 293                 return 1;
 294 
 295         if (a->type != b->type)
 296                 return 1;
 297 
 298         if (a->type == LWTUNNEL_ENCAP_NONE ||
 299             a->type > LWTUNNEL_ENCAP_MAX)
 300                 return 0;
 301 
 302         rcu_read_lock();
 303         ops = rcu_dereference(lwtun_encaps[a->type]);
 304         if (likely(ops && ops->cmp_encap))
 305                 ret = ops->cmp_encap(a, b);
 306         rcu_read_unlock();
 307 
 308         return ret;
 309 }
 310 EXPORT_SYMBOL_GPL(lwtunnel_cmp_encap);
 311 
 312 int lwtunnel_output(struct net *net, struct sock *sk, struct sk_buff *skb)
 313 {
 314         struct dst_entry *dst = skb_dst(skb);
 315         const struct lwtunnel_encap_ops *ops;
 316         struct lwtunnel_state *lwtstate;
 317         int ret = -EINVAL;
 318 
 319         if (!dst)
 320                 goto drop;
 321         lwtstate = dst->lwtstate;
 322 
 323         if (lwtstate->type == LWTUNNEL_ENCAP_NONE ||
 324             lwtstate->type > LWTUNNEL_ENCAP_MAX)
 325                 return 0;
 326 
 327         ret = -EOPNOTSUPP;
 328         rcu_read_lock();
 329         ops = rcu_dereference(lwtun_encaps[lwtstate->type]);
 330         if (likely(ops && ops->output))
 331                 ret = ops->output(net, sk, skb);
 332         rcu_read_unlock();
 333 
 334         if (ret == -EOPNOTSUPP)
 335                 goto drop;
 336 
 337         return ret;
 338 
 339 drop:
 340         kfree_skb(skb);
 341 
 342         return ret;
 343 }
 344 EXPORT_SYMBOL_GPL(lwtunnel_output);
 345 
 346 int lwtunnel_xmit(struct sk_buff *skb)
 347 {
 348         struct dst_entry *dst = skb_dst(skb);
 349         const struct lwtunnel_encap_ops *ops;
 350         struct lwtunnel_state *lwtstate;
 351         int ret = -EINVAL;
 352 
 353         if (!dst)
 354                 goto drop;
 355 
 356         lwtstate = dst->lwtstate;
 357 
 358         if (lwtstate->type == LWTUNNEL_ENCAP_NONE ||
 359             lwtstate->type > LWTUNNEL_ENCAP_MAX)
 360                 return 0;
 361 
 362         ret = -EOPNOTSUPP;
 363         rcu_read_lock();
 364         ops = rcu_dereference(lwtun_encaps[lwtstate->type]);
 365         if (likely(ops && ops->xmit))
 366                 ret = ops->xmit(skb);
 367         rcu_read_unlock();
 368 
 369         if (ret == -EOPNOTSUPP)
 370                 goto drop;
 371 
 372         return ret;
 373 
 374 drop:
 375         kfree_skb(skb);
 376 
 377         return ret;
 378 }
 379 EXPORT_SYMBOL_GPL(lwtunnel_xmit);
 380 
 381 int lwtunnel_input(struct sk_buff *skb)
 382 {
 383         struct dst_entry *dst = skb_dst(skb);
 384         const struct lwtunnel_encap_ops *ops;
 385         struct lwtunnel_state *lwtstate;
 386         int ret = -EINVAL;
 387 
 388         if (!dst)
 389                 goto drop;
 390         lwtstate = dst->lwtstate;
 391 
 392         if (lwtstate->type == LWTUNNEL_ENCAP_NONE ||
 393             lwtstate->type > LWTUNNEL_ENCAP_MAX)
 394                 return 0;
 395 
 396         ret = -EOPNOTSUPP;
 397         rcu_read_lock();
 398         ops = rcu_dereference(lwtun_encaps[lwtstate->type]);
 399         if (likely(ops && ops->input))
 400                 ret = ops->input(skb);
 401         rcu_read_unlock();
 402 
 403         if (ret == -EOPNOTSUPP)
 404                 goto drop;
 405 
 406         return ret;
 407 
 408 drop:
 409         kfree_skb(skb);
 410 
 411         return ret;
 412 }
 413 EXPORT_SYMBOL_GPL(lwtunnel_input);

/* [<][>][^][v][top][bottom][index][help] */