Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * lwtunnel Infrastructure for light weight tunnels like mpls
0004  *
0005  * Authors: Roopa Prabhu, <roopa@cumulusnetworks.com>
0006  */
0007 
0008 #include <linux/capability.h>
0009 #include <linux/module.h>
0010 #include <linux/types.h>
0011 #include <linux/kernel.h>
0012 #include <linux/slab.h>
0013 #include <linux/uaccess.h>
0014 #include <linux/skbuff.h>
0015 #include <linux/netdevice.h>
0016 #include <linux/lwtunnel.h>
0017 #include <linux/in.h>
0018 #include <linux/init.h>
0019 #include <linux/err.h>
0020 
0021 #include <net/lwtunnel.h>
0022 #include <net/rtnetlink.h>
0023 #include <net/ip6_fib.h>
0024 #include <net/rtnh.h>
0025 
0026 DEFINE_STATIC_KEY_FALSE(nf_hooks_lwtunnel_enabled);
0027 EXPORT_SYMBOL_GPL(nf_hooks_lwtunnel_enabled);
0028 
0029 #ifdef CONFIG_MODULES
0030 
0031 static const char *lwtunnel_encap_str(enum lwtunnel_encap_types encap_type)
0032 {
0033     /* Only lwt encaps implemented without using an interface for
0034      * the encap need to return a string here.
0035      */
0036     switch (encap_type) {
0037     case LWTUNNEL_ENCAP_MPLS:
0038         return "MPLS";
0039     case LWTUNNEL_ENCAP_ILA:
0040         return "ILA";
0041     case LWTUNNEL_ENCAP_SEG6:
0042         return "SEG6";
0043     case LWTUNNEL_ENCAP_BPF:
0044         return "BPF";
0045     case LWTUNNEL_ENCAP_SEG6_LOCAL:
0046         return "SEG6LOCAL";
0047     case LWTUNNEL_ENCAP_RPL:
0048         return "RPL";
0049     case LWTUNNEL_ENCAP_IOAM6:
0050         return "IOAM6";
0051     case LWTUNNEL_ENCAP_IP6:
0052     case LWTUNNEL_ENCAP_IP:
0053     case LWTUNNEL_ENCAP_NONE:
0054     case __LWTUNNEL_ENCAP_MAX:
0055         /* should not have got here */
0056         WARN_ON(1);
0057         break;
0058     }
0059     return NULL;
0060 }
0061 
0062 #endif /* CONFIG_MODULES */
0063 
0064 struct lwtunnel_state *lwtunnel_state_alloc(int encap_len)
0065 {
0066     struct lwtunnel_state *lws;
0067 
0068     lws = kzalloc(sizeof(*lws) + encap_len, GFP_ATOMIC);
0069 
0070     return lws;
0071 }
0072 EXPORT_SYMBOL_GPL(lwtunnel_state_alloc);
0073 
0074 static const struct lwtunnel_encap_ops __rcu *
0075         lwtun_encaps[LWTUNNEL_ENCAP_MAX + 1] __read_mostly;
0076 
0077 int lwtunnel_encap_add_ops(const struct lwtunnel_encap_ops *ops,
0078                unsigned int num)
0079 {
0080     if (num > LWTUNNEL_ENCAP_MAX)
0081         return -ERANGE;
0082 
0083     return !cmpxchg((const struct lwtunnel_encap_ops **)
0084             &lwtun_encaps[num],
0085             NULL, ops) ? 0 : -1;
0086 }
0087 EXPORT_SYMBOL_GPL(lwtunnel_encap_add_ops);
0088 
0089 int lwtunnel_encap_del_ops(const struct lwtunnel_encap_ops *ops,
0090                unsigned int encap_type)
0091 {
0092     int ret;
0093 
0094     if (encap_type == LWTUNNEL_ENCAP_NONE ||
0095         encap_type > LWTUNNEL_ENCAP_MAX)
0096         return -ERANGE;
0097 
0098     ret = (cmpxchg((const struct lwtunnel_encap_ops **)
0099                &lwtun_encaps[encap_type],
0100                ops, NULL) == ops) ? 0 : -1;
0101 
0102     synchronize_net();
0103 
0104     return ret;
0105 }
0106 EXPORT_SYMBOL_GPL(lwtunnel_encap_del_ops);
0107 
0108 int lwtunnel_build_state(struct net *net, u16 encap_type,
0109              struct nlattr *encap, unsigned int family,
0110              const void *cfg, struct lwtunnel_state **lws,
0111              struct netlink_ext_ack *extack)
0112 {
0113     const struct lwtunnel_encap_ops *ops;
0114     bool found = false;
0115     int ret = -EINVAL;
0116 
0117     if (encap_type == LWTUNNEL_ENCAP_NONE ||
0118         encap_type > LWTUNNEL_ENCAP_MAX) {
0119         NL_SET_ERR_MSG_ATTR(extack, encap,
0120                     "Unknown LWT encapsulation type");
0121         return ret;
0122     }
0123 
0124     ret = -EOPNOTSUPP;
0125     rcu_read_lock();
0126     ops = rcu_dereference(lwtun_encaps[encap_type]);
0127     if (likely(ops && ops->build_state && try_module_get(ops->owner)))
0128         found = true;
0129     rcu_read_unlock();
0130 
0131     if (found) {
0132         ret = ops->build_state(net, encap, family, cfg, lws, extack);
0133         if (ret)
0134             module_put(ops->owner);
0135     } else {
0136         /* don't rely on -EOPNOTSUPP to detect match as build_state
0137          * handlers could return it
0138          */
0139         NL_SET_ERR_MSG_ATTR(extack, encap,
0140                     "LWT encapsulation type not supported");
0141     }
0142 
0143     return ret;
0144 }
0145 EXPORT_SYMBOL_GPL(lwtunnel_build_state);
0146 
0147 int lwtunnel_valid_encap_type(u16 encap_type, struct netlink_ext_ack *extack)
0148 {
0149     const struct lwtunnel_encap_ops *ops;
0150     int ret = -EINVAL;
0151 
0152     if (encap_type == LWTUNNEL_ENCAP_NONE ||
0153         encap_type > LWTUNNEL_ENCAP_MAX) {
0154         NL_SET_ERR_MSG(extack, "Unknown lwt encapsulation type");
0155         return ret;
0156     }
0157 
0158     rcu_read_lock();
0159     ops = rcu_dereference(lwtun_encaps[encap_type]);
0160     rcu_read_unlock();
0161 #ifdef CONFIG_MODULES
0162     if (!ops) {
0163         const char *encap_type_str = lwtunnel_encap_str(encap_type);
0164 
0165         if (encap_type_str) {
0166             __rtnl_unlock();
0167             request_module("rtnl-lwt-%s", encap_type_str);
0168             rtnl_lock();
0169 
0170             rcu_read_lock();
0171             ops = rcu_dereference(lwtun_encaps[encap_type]);
0172             rcu_read_unlock();
0173         }
0174     }
0175 #endif
0176     ret = ops ? 0 : -EOPNOTSUPP;
0177     if (ret < 0)
0178         NL_SET_ERR_MSG(extack, "lwt encapsulation type not supported");
0179 
0180     return ret;
0181 }
0182 EXPORT_SYMBOL_GPL(lwtunnel_valid_encap_type);
0183 
0184 int lwtunnel_valid_encap_type_attr(struct nlattr *attr, int remaining,
0185                    struct netlink_ext_ack *extack)
0186 {
0187     struct rtnexthop *rtnh = (struct rtnexthop *)attr;
0188     struct nlattr *nla_entype;
0189     struct nlattr *attrs;
0190     u16 encap_type;
0191     int attrlen;
0192 
0193     while (rtnh_ok(rtnh, remaining)) {
0194         attrlen = rtnh_attrlen(rtnh);
0195         if (attrlen > 0) {
0196             attrs = rtnh_attrs(rtnh);
0197             nla_entype = nla_find(attrs, attrlen, RTA_ENCAP_TYPE);
0198 
0199             if (nla_entype) {
0200                 if (nla_len(nla_entype) < sizeof(u16)) {
0201                     NL_SET_ERR_MSG(extack, "Invalid RTA_ENCAP_TYPE");
0202                     return -EINVAL;
0203                 }
0204                 encap_type = nla_get_u16(nla_entype);
0205 
0206                 if (lwtunnel_valid_encap_type(encap_type,
0207                                   extack) != 0)
0208                     return -EOPNOTSUPP;
0209             }
0210         }
0211         rtnh = rtnh_next(rtnh, &remaining);
0212     }
0213 
0214     return 0;
0215 }
0216 EXPORT_SYMBOL_GPL(lwtunnel_valid_encap_type_attr);
0217 
0218 void lwtstate_free(struct lwtunnel_state *lws)
0219 {
0220     const struct lwtunnel_encap_ops *ops = lwtun_encaps[lws->type];
0221 
0222     if (ops->destroy_state) {
0223         ops->destroy_state(lws);
0224         kfree_rcu(lws, rcu);
0225     } else {
0226         kfree(lws);
0227     }
0228     module_put(ops->owner);
0229 }
0230 EXPORT_SYMBOL_GPL(lwtstate_free);
0231 
0232 int lwtunnel_fill_encap(struct sk_buff *skb, struct lwtunnel_state *lwtstate,
0233             int encap_attr, int encap_type_attr)
0234 {
0235     const struct lwtunnel_encap_ops *ops;
0236     struct nlattr *nest;
0237     int ret;
0238 
0239     if (!lwtstate)
0240         return 0;
0241 
0242     if (lwtstate->type == LWTUNNEL_ENCAP_NONE ||
0243         lwtstate->type > LWTUNNEL_ENCAP_MAX)
0244         return 0;
0245 
0246     nest = nla_nest_start_noflag(skb, encap_attr);
0247     if (!nest)
0248         return -EMSGSIZE;
0249 
0250     ret = -EOPNOTSUPP;
0251     rcu_read_lock();
0252     ops = rcu_dereference(lwtun_encaps[lwtstate->type]);
0253     if (likely(ops && ops->fill_encap))
0254         ret = ops->fill_encap(skb, lwtstate);
0255     rcu_read_unlock();
0256 
0257     if (ret)
0258         goto nla_put_failure;
0259     nla_nest_end(skb, nest);
0260     ret = nla_put_u16(skb, encap_type_attr, lwtstate->type);
0261     if (ret)
0262         goto nla_put_failure;
0263 
0264     return 0;
0265 
0266 nla_put_failure:
0267     nla_nest_cancel(skb, nest);
0268 
0269     return (ret == -EOPNOTSUPP ? 0 : ret);
0270 }
0271 EXPORT_SYMBOL_GPL(lwtunnel_fill_encap);
0272 
0273 int lwtunnel_get_encap_size(struct lwtunnel_state *lwtstate)
0274 {
0275     const struct lwtunnel_encap_ops *ops;
0276     int ret = 0;
0277 
0278     if (!lwtstate)
0279         return 0;
0280 
0281     if (lwtstate->type == LWTUNNEL_ENCAP_NONE ||
0282         lwtstate->type > LWTUNNEL_ENCAP_MAX)
0283         return 0;
0284 
0285     rcu_read_lock();
0286     ops = rcu_dereference(lwtun_encaps[lwtstate->type]);
0287     if (likely(ops && ops->get_encap_size))
0288         ret = nla_total_size(ops->get_encap_size(lwtstate));
0289     rcu_read_unlock();
0290 
0291     return ret;
0292 }
0293 EXPORT_SYMBOL_GPL(lwtunnel_get_encap_size);
0294 
0295 int lwtunnel_cmp_encap(struct lwtunnel_state *a, struct lwtunnel_state *b)
0296 {
0297     const struct lwtunnel_encap_ops *ops;
0298     int ret = 0;
0299 
0300     if (!a && !b)
0301         return 0;
0302 
0303     if (!a || !b)
0304         return 1;
0305 
0306     if (a->type != b->type)
0307         return 1;
0308 
0309     if (a->type == LWTUNNEL_ENCAP_NONE ||
0310         a->type > LWTUNNEL_ENCAP_MAX)
0311         return 0;
0312 
0313     rcu_read_lock();
0314     ops = rcu_dereference(lwtun_encaps[a->type]);
0315     if (likely(ops && ops->cmp_encap))
0316         ret = ops->cmp_encap(a, b);
0317     rcu_read_unlock();
0318 
0319     return ret;
0320 }
0321 EXPORT_SYMBOL_GPL(lwtunnel_cmp_encap);
0322 
0323 int lwtunnel_output(struct net *net, struct sock *sk, struct sk_buff *skb)
0324 {
0325     struct dst_entry *dst = skb_dst(skb);
0326     const struct lwtunnel_encap_ops *ops;
0327     struct lwtunnel_state *lwtstate;
0328     int ret = -EINVAL;
0329 
0330     if (!dst)
0331         goto drop;
0332     lwtstate = dst->lwtstate;
0333 
0334     if (lwtstate->type == LWTUNNEL_ENCAP_NONE ||
0335         lwtstate->type > LWTUNNEL_ENCAP_MAX)
0336         return 0;
0337 
0338     ret = -EOPNOTSUPP;
0339     rcu_read_lock();
0340     ops = rcu_dereference(lwtun_encaps[lwtstate->type]);
0341     if (likely(ops && ops->output))
0342         ret = ops->output(net, sk, skb);
0343     rcu_read_unlock();
0344 
0345     if (ret == -EOPNOTSUPP)
0346         goto drop;
0347 
0348     return ret;
0349 
0350 drop:
0351     kfree_skb(skb);
0352 
0353     return ret;
0354 }
0355 EXPORT_SYMBOL_GPL(lwtunnel_output);
0356 
0357 int lwtunnel_xmit(struct sk_buff *skb)
0358 {
0359     struct dst_entry *dst = skb_dst(skb);
0360     const struct lwtunnel_encap_ops *ops;
0361     struct lwtunnel_state *lwtstate;
0362     int ret = -EINVAL;
0363 
0364     if (!dst)
0365         goto drop;
0366 
0367     lwtstate = dst->lwtstate;
0368 
0369     if (lwtstate->type == LWTUNNEL_ENCAP_NONE ||
0370         lwtstate->type > LWTUNNEL_ENCAP_MAX)
0371         return 0;
0372 
0373     ret = -EOPNOTSUPP;
0374     rcu_read_lock();
0375     ops = rcu_dereference(lwtun_encaps[lwtstate->type]);
0376     if (likely(ops && ops->xmit))
0377         ret = ops->xmit(skb);
0378     rcu_read_unlock();
0379 
0380     if (ret == -EOPNOTSUPP)
0381         goto drop;
0382 
0383     return ret;
0384 
0385 drop:
0386     kfree_skb(skb);
0387 
0388     return ret;
0389 }
0390 EXPORT_SYMBOL_GPL(lwtunnel_xmit);
0391 
0392 int lwtunnel_input(struct sk_buff *skb)
0393 {
0394     struct dst_entry *dst = skb_dst(skb);
0395     const struct lwtunnel_encap_ops *ops;
0396     struct lwtunnel_state *lwtstate;
0397     int ret = -EINVAL;
0398 
0399     if (!dst)
0400         goto drop;
0401     lwtstate = dst->lwtstate;
0402 
0403     if (lwtstate->type == LWTUNNEL_ENCAP_NONE ||
0404         lwtstate->type > LWTUNNEL_ENCAP_MAX)
0405         return 0;
0406 
0407     ret = -EOPNOTSUPP;
0408     rcu_read_lock();
0409     ops = rcu_dereference(lwtun_encaps[lwtstate->type]);
0410     if (likely(ops && ops->input))
0411         ret = ops->input(skb);
0412     rcu_read_unlock();
0413 
0414     if (ret == -EOPNOTSUPP)
0415         goto drop;
0416 
0417     return ret;
0418 
0419 drop:
0420     kfree_skb(skb);
0421 
0422     return ret;
0423 }
0424 EXPORT_SYMBOL_GPL(lwtunnel_input);