root/net/sched/act_mpls.c

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

DEFINITIONS

This source file includes following definitions.
  1. tcf_mpls_get_lse
  2. tcf_mpls_act
  3. valid_label
  4. tcf_mpls_init
  5. tcf_mpls_cleanup
  6. tcf_mpls_dump
  7. tcf_mpls_walker
  8. tcf_mpls_search
  9. mpls_init_net
  10. mpls_exit_net
  11. mpls_init_module
  12. mpls_cleanup_module

   1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
   2 /* Copyright (C) 2019 Netronome Systems, Inc. */
   3 
   4 #include <linux/if_arp.h>
   5 #include <linux/init.h>
   6 #include <linux/kernel.h>
   7 #include <linux/module.h>
   8 #include <linux/mpls.h>
   9 #include <linux/rtnetlink.h>
  10 #include <linux/skbuff.h>
  11 #include <linux/tc_act/tc_mpls.h>
  12 #include <net/mpls.h>
  13 #include <net/netlink.h>
  14 #include <net/pkt_sched.h>
  15 #include <net/pkt_cls.h>
  16 #include <net/tc_act/tc_mpls.h>
  17 
  18 static unsigned int mpls_net_id;
  19 static struct tc_action_ops act_mpls_ops;
  20 
  21 #define ACT_MPLS_TTL_DEFAULT    255
  22 
  23 static __be32 tcf_mpls_get_lse(struct mpls_shim_hdr *lse,
  24                                struct tcf_mpls_params *p, bool set_bos)
  25 {
  26         u32 new_lse = 0;
  27 
  28         if (lse)
  29                 new_lse = be32_to_cpu(lse->label_stack_entry);
  30 
  31         if (p->tcfm_label != ACT_MPLS_LABEL_NOT_SET) {
  32                 new_lse &= ~MPLS_LS_LABEL_MASK;
  33                 new_lse |= p->tcfm_label << MPLS_LS_LABEL_SHIFT;
  34         }
  35         if (p->tcfm_ttl) {
  36                 new_lse &= ~MPLS_LS_TTL_MASK;
  37                 new_lse |= p->tcfm_ttl << MPLS_LS_TTL_SHIFT;
  38         }
  39         if (p->tcfm_tc != ACT_MPLS_TC_NOT_SET) {
  40                 new_lse &= ~MPLS_LS_TC_MASK;
  41                 new_lse |= p->tcfm_tc << MPLS_LS_TC_SHIFT;
  42         }
  43         if (p->tcfm_bos != ACT_MPLS_BOS_NOT_SET) {
  44                 new_lse &= ~MPLS_LS_S_MASK;
  45                 new_lse |= p->tcfm_bos << MPLS_LS_S_SHIFT;
  46         } else if (set_bos) {
  47                 new_lse |= 1 << MPLS_LS_S_SHIFT;
  48         }
  49 
  50         return cpu_to_be32(new_lse);
  51 }
  52 
  53 static int tcf_mpls_act(struct sk_buff *skb, const struct tc_action *a,
  54                         struct tcf_result *res)
  55 {
  56         struct tcf_mpls *m = to_mpls(a);
  57         struct tcf_mpls_params *p;
  58         __be32 new_lse;
  59         int ret, mac_len;
  60 
  61         tcf_lastuse_update(&m->tcf_tm);
  62         bstats_cpu_update(this_cpu_ptr(m->common.cpu_bstats), skb);
  63 
  64         /* Ensure 'data' points at mac_header prior calling mpls manipulating
  65          * functions.
  66          */
  67         if (skb_at_tc_ingress(skb)) {
  68                 skb_push_rcsum(skb, skb->mac_len);
  69                 mac_len = skb->mac_len;
  70         } else {
  71                 mac_len = skb_network_header(skb) - skb_mac_header(skb);
  72         }
  73 
  74         ret = READ_ONCE(m->tcf_action);
  75 
  76         p = rcu_dereference_bh(m->mpls_p);
  77 
  78         switch (p->tcfm_action) {
  79         case TCA_MPLS_ACT_POP:
  80                 if (skb_mpls_pop(skb, p->tcfm_proto, mac_len,
  81                                  skb->dev && skb->dev->type == ARPHRD_ETHER))
  82                         goto drop;
  83                 break;
  84         case TCA_MPLS_ACT_PUSH:
  85                 new_lse = tcf_mpls_get_lse(NULL, p, !eth_p_mpls(skb->protocol));
  86                 if (skb_mpls_push(skb, new_lse, p->tcfm_proto, mac_len,
  87                                   skb->dev && skb->dev->type == ARPHRD_ETHER))
  88                         goto drop;
  89                 break;
  90         case TCA_MPLS_ACT_MODIFY:
  91                 new_lse = tcf_mpls_get_lse(mpls_hdr(skb), p, false);
  92                 if (skb_mpls_update_lse(skb, new_lse))
  93                         goto drop;
  94                 break;
  95         case TCA_MPLS_ACT_DEC_TTL:
  96                 if (skb_mpls_dec_ttl(skb))
  97                         goto drop;
  98                 break;
  99         }
 100 
 101         if (skb_at_tc_ingress(skb))
 102                 skb_pull_rcsum(skb, skb->mac_len);
 103 
 104         return ret;
 105 
 106 drop:
 107         qstats_drop_inc(this_cpu_ptr(m->common.cpu_qstats));
 108         return TC_ACT_SHOT;
 109 }
 110 
 111 static int valid_label(const struct nlattr *attr,
 112                        struct netlink_ext_ack *extack)
 113 {
 114         const u32 *label = nla_data(attr);
 115 
 116         if (*label & ~MPLS_LABEL_MASK || *label == MPLS_LABEL_IMPLNULL) {
 117                 NL_SET_ERR_MSG_MOD(extack, "MPLS label out of range");
 118                 return -EINVAL;
 119         }
 120 
 121         return 0;
 122 }
 123 
 124 static const struct nla_policy mpls_policy[TCA_MPLS_MAX + 1] = {
 125         [TCA_MPLS_UNSPEC]       = { .strict_start_type = TCA_MPLS_UNSPEC + 1 },
 126         [TCA_MPLS_PARMS]        = NLA_POLICY_EXACT_LEN(sizeof(struct tc_mpls)),
 127         [TCA_MPLS_PROTO]        = { .type = NLA_U16 },
 128         [TCA_MPLS_LABEL]        = NLA_POLICY_VALIDATE_FN(NLA_U32, valid_label),
 129         [TCA_MPLS_TC]           = NLA_POLICY_RANGE(NLA_U8, 0, 7),
 130         [TCA_MPLS_TTL]          = NLA_POLICY_MIN(NLA_U8, 1),
 131         [TCA_MPLS_BOS]          = NLA_POLICY_RANGE(NLA_U8, 0, 1),
 132 };
 133 
 134 static int tcf_mpls_init(struct net *net, struct nlattr *nla,
 135                          struct nlattr *est, struct tc_action **a,
 136                          int ovr, int bind, bool rtnl_held,
 137                          struct tcf_proto *tp, struct netlink_ext_ack *extack)
 138 {
 139         struct tc_action_net *tn = net_generic(net, mpls_net_id);
 140         struct nlattr *tb[TCA_MPLS_MAX + 1];
 141         struct tcf_chain *goto_ch = NULL;
 142         struct tcf_mpls_params *p;
 143         struct tc_mpls *parm;
 144         bool exists = false;
 145         struct tcf_mpls *m;
 146         int ret = 0, err;
 147         u8 mpls_ttl = 0;
 148         u32 index;
 149 
 150         if (!nla) {
 151                 NL_SET_ERR_MSG_MOD(extack, "Missing netlink attributes");
 152                 return -EINVAL;
 153         }
 154 
 155         err = nla_parse_nested(tb, TCA_MPLS_MAX, nla, mpls_policy, extack);
 156         if (err < 0)
 157                 return err;
 158 
 159         if (!tb[TCA_MPLS_PARMS]) {
 160                 NL_SET_ERR_MSG_MOD(extack, "No MPLS params");
 161                 return -EINVAL;
 162         }
 163         parm = nla_data(tb[TCA_MPLS_PARMS]);
 164         index = parm->index;
 165 
 166         /* Verify parameters against action type. */
 167         switch (parm->m_action) {
 168         case TCA_MPLS_ACT_POP:
 169                 if (!tb[TCA_MPLS_PROTO]) {
 170                         NL_SET_ERR_MSG_MOD(extack, "Protocol must be set for MPLS pop");
 171                         return -EINVAL;
 172                 }
 173                 if (!eth_proto_is_802_3(nla_get_be16(tb[TCA_MPLS_PROTO]))) {
 174                         NL_SET_ERR_MSG_MOD(extack, "Invalid protocol type for MPLS pop");
 175                         return -EINVAL;
 176                 }
 177                 if (tb[TCA_MPLS_LABEL] || tb[TCA_MPLS_TTL] || tb[TCA_MPLS_TC] ||
 178                     tb[TCA_MPLS_BOS]) {
 179                         NL_SET_ERR_MSG_MOD(extack, "Label, TTL, TC or BOS cannot be used with MPLS pop");
 180                         return -EINVAL;
 181                 }
 182                 break;
 183         case TCA_MPLS_ACT_DEC_TTL:
 184                 if (tb[TCA_MPLS_PROTO] || tb[TCA_MPLS_LABEL] ||
 185                     tb[TCA_MPLS_TTL] || tb[TCA_MPLS_TC] || tb[TCA_MPLS_BOS]) {
 186                         NL_SET_ERR_MSG_MOD(extack, "Label, TTL, TC, BOS or protocol cannot be used with MPLS dec_ttl");
 187                         return -EINVAL;
 188                 }
 189                 break;
 190         case TCA_MPLS_ACT_PUSH:
 191                 if (!tb[TCA_MPLS_LABEL]) {
 192                         NL_SET_ERR_MSG_MOD(extack, "Label is required for MPLS push");
 193                         return -EINVAL;
 194                 }
 195                 if (tb[TCA_MPLS_PROTO] &&
 196                     !eth_p_mpls(nla_get_be16(tb[TCA_MPLS_PROTO]))) {
 197                         NL_SET_ERR_MSG_MOD(extack, "Protocol must be an MPLS type for MPLS push");
 198                         return -EPROTONOSUPPORT;
 199                 }
 200                 /* Push needs a TTL - if not specified, set a default value. */
 201                 if (!tb[TCA_MPLS_TTL]) {
 202 #if IS_ENABLED(CONFIG_MPLS)
 203                         mpls_ttl = net->mpls.default_ttl ?
 204                                    net->mpls.default_ttl : ACT_MPLS_TTL_DEFAULT;
 205 #else
 206                         mpls_ttl = ACT_MPLS_TTL_DEFAULT;
 207 #endif
 208                 }
 209                 break;
 210         case TCA_MPLS_ACT_MODIFY:
 211                 if (tb[TCA_MPLS_PROTO]) {
 212                         NL_SET_ERR_MSG_MOD(extack, "Protocol cannot be used with MPLS modify");
 213                         return -EINVAL;
 214                 }
 215                 break;
 216         default:
 217                 NL_SET_ERR_MSG_MOD(extack, "Unknown MPLS action");
 218                 return -EINVAL;
 219         }
 220 
 221         err = tcf_idr_check_alloc(tn, &index, a, bind);
 222         if (err < 0)
 223                 return err;
 224         exists = err;
 225         if (exists && bind)
 226                 return 0;
 227 
 228         if (!exists) {
 229                 ret = tcf_idr_create(tn, index, est, a,
 230                                      &act_mpls_ops, bind, true);
 231                 if (ret) {
 232                         tcf_idr_cleanup(tn, index);
 233                         return ret;
 234                 }
 235 
 236                 ret = ACT_P_CREATED;
 237         } else if (!ovr) {
 238                 tcf_idr_release(*a, bind);
 239                 return -EEXIST;
 240         }
 241 
 242         err = tcf_action_check_ctrlact(parm->action, tp, &goto_ch, extack);
 243         if (err < 0)
 244                 goto release_idr;
 245 
 246         m = to_mpls(*a);
 247 
 248         p = kzalloc(sizeof(*p), GFP_KERNEL);
 249         if (!p) {
 250                 err = -ENOMEM;
 251                 goto put_chain;
 252         }
 253 
 254         p->tcfm_action = parm->m_action;
 255         p->tcfm_label = tb[TCA_MPLS_LABEL] ? nla_get_u32(tb[TCA_MPLS_LABEL]) :
 256                                              ACT_MPLS_LABEL_NOT_SET;
 257         p->tcfm_tc = tb[TCA_MPLS_TC] ? nla_get_u8(tb[TCA_MPLS_TC]) :
 258                                        ACT_MPLS_TC_NOT_SET;
 259         p->tcfm_ttl = tb[TCA_MPLS_TTL] ? nla_get_u8(tb[TCA_MPLS_TTL]) :
 260                                          mpls_ttl;
 261         p->tcfm_bos = tb[TCA_MPLS_BOS] ? nla_get_u8(tb[TCA_MPLS_BOS]) :
 262                                          ACT_MPLS_BOS_NOT_SET;
 263         p->tcfm_proto = tb[TCA_MPLS_PROTO] ? nla_get_be16(tb[TCA_MPLS_PROTO]) :
 264                                              htons(ETH_P_MPLS_UC);
 265 
 266         spin_lock_bh(&m->tcf_lock);
 267         goto_ch = tcf_action_set_ctrlact(*a, parm->action, goto_ch);
 268         rcu_swap_protected(m->mpls_p, p, lockdep_is_held(&m->tcf_lock));
 269         spin_unlock_bh(&m->tcf_lock);
 270 
 271         if (goto_ch)
 272                 tcf_chain_put_by_act(goto_ch);
 273         if (p)
 274                 kfree_rcu(p, rcu);
 275 
 276         if (ret == ACT_P_CREATED)
 277                 tcf_idr_insert(tn, *a);
 278         return ret;
 279 put_chain:
 280         if (goto_ch)
 281                 tcf_chain_put_by_act(goto_ch);
 282 release_idr:
 283         tcf_idr_release(*a, bind);
 284         return err;
 285 }
 286 
 287 static void tcf_mpls_cleanup(struct tc_action *a)
 288 {
 289         struct tcf_mpls *m = to_mpls(a);
 290         struct tcf_mpls_params *p;
 291 
 292         p = rcu_dereference_protected(m->mpls_p, 1);
 293         if (p)
 294                 kfree_rcu(p, rcu);
 295 }
 296 
 297 static int tcf_mpls_dump(struct sk_buff *skb, struct tc_action *a,
 298                          int bind, int ref)
 299 {
 300         unsigned char *b = skb_tail_pointer(skb);
 301         struct tcf_mpls *m = to_mpls(a);
 302         struct tcf_mpls_params *p;
 303         struct tc_mpls opt = {
 304                 .index    = m->tcf_index,
 305                 .refcnt   = refcount_read(&m->tcf_refcnt) - ref,
 306                 .bindcnt  = atomic_read(&m->tcf_bindcnt) - bind,
 307         };
 308         struct tcf_t t;
 309 
 310         spin_lock_bh(&m->tcf_lock);
 311         opt.action = m->tcf_action;
 312         p = rcu_dereference_protected(m->mpls_p, lockdep_is_held(&m->tcf_lock));
 313         opt.m_action = p->tcfm_action;
 314 
 315         if (nla_put(skb, TCA_MPLS_PARMS, sizeof(opt), &opt))
 316                 goto nla_put_failure;
 317 
 318         if (p->tcfm_label != ACT_MPLS_LABEL_NOT_SET &&
 319             nla_put_u32(skb, TCA_MPLS_LABEL, p->tcfm_label))
 320                 goto nla_put_failure;
 321 
 322         if (p->tcfm_tc != ACT_MPLS_TC_NOT_SET &&
 323             nla_put_u8(skb, TCA_MPLS_TC, p->tcfm_tc))
 324                 goto nla_put_failure;
 325 
 326         if (p->tcfm_ttl && nla_put_u8(skb, TCA_MPLS_TTL, p->tcfm_ttl))
 327                 goto nla_put_failure;
 328 
 329         if (p->tcfm_bos != ACT_MPLS_BOS_NOT_SET &&
 330             nla_put_u8(skb, TCA_MPLS_BOS, p->tcfm_bos))
 331                 goto nla_put_failure;
 332 
 333         if (nla_put_be16(skb, TCA_MPLS_PROTO, p->tcfm_proto))
 334                 goto nla_put_failure;
 335 
 336         tcf_tm_dump(&t, &m->tcf_tm);
 337 
 338         if (nla_put_64bit(skb, TCA_MPLS_TM, sizeof(t), &t, TCA_MPLS_PAD))
 339                 goto nla_put_failure;
 340 
 341         spin_unlock_bh(&m->tcf_lock);
 342 
 343         return skb->len;
 344 
 345 nla_put_failure:
 346         spin_unlock_bh(&m->tcf_lock);
 347         nlmsg_trim(skb, b);
 348         return -EMSGSIZE;
 349 }
 350 
 351 static int tcf_mpls_walker(struct net *net, struct sk_buff *skb,
 352                            struct netlink_callback *cb, int type,
 353                            const struct tc_action_ops *ops,
 354                            struct netlink_ext_ack *extack)
 355 {
 356         struct tc_action_net *tn = net_generic(net, mpls_net_id);
 357 
 358         return tcf_generic_walker(tn, skb, cb, type, ops, extack);
 359 }
 360 
 361 static int tcf_mpls_search(struct net *net, struct tc_action **a, u32 index)
 362 {
 363         struct tc_action_net *tn = net_generic(net, mpls_net_id);
 364 
 365         return tcf_idr_search(tn, a, index);
 366 }
 367 
 368 static struct tc_action_ops act_mpls_ops = {
 369         .kind           =       "mpls",
 370         .id             =       TCA_ID_MPLS,
 371         .owner          =       THIS_MODULE,
 372         .act            =       tcf_mpls_act,
 373         .dump           =       tcf_mpls_dump,
 374         .init           =       tcf_mpls_init,
 375         .cleanup        =       tcf_mpls_cleanup,
 376         .walk           =       tcf_mpls_walker,
 377         .lookup         =       tcf_mpls_search,
 378         .size           =       sizeof(struct tcf_mpls),
 379 };
 380 
 381 static __net_init int mpls_init_net(struct net *net)
 382 {
 383         struct tc_action_net *tn = net_generic(net, mpls_net_id);
 384 
 385         return tc_action_net_init(net, tn, &act_mpls_ops);
 386 }
 387 
 388 static void __net_exit mpls_exit_net(struct list_head *net_list)
 389 {
 390         tc_action_net_exit(net_list, mpls_net_id);
 391 }
 392 
 393 static struct pernet_operations mpls_net_ops = {
 394         .init = mpls_init_net,
 395         .exit_batch = mpls_exit_net,
 396         .id   = &mpls_net_id,
 397         .size = sizeof(struct tc_action_net),
 398 };
 399 
 400 static int __init mpls_init_module(void)
 401 {
 402         return tcf_register_action(&act_mpls_ops, &mpls_net_ops);
 403 }
 404 
 405 static void __exit mpls_cleanup_module(void)
 406 {
 407         tcf_unregister_action(&act_mpls_ops, &mpls_net_ops);
 408 }
 409 
 410 module_init(mpls_init_module);
 411 module_exit(mpls_cleanup_module);
 412 
 413 MODULE_AUTHOR("Netronome Systems <oss-drivers@netronome.com>");
 414 MODULE_LICENSE("GPL");
 415 MODULE_DESCRIPTION("MPLS manipulation actions");

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