linux/net/sched/act_mpls.c
<<
>>
Prefs
   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
  18static unsigned int mpls_net_id;
  19static struct tc_action_ops act_mpls_ops;
  20
  21#define ACT_MPLS_TTL_DEFAULT    255
  22
  23static __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
  53static 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(skb, true)));
  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_MAC_PUSH:
  91                if (skb_vlan_tag_present(skb)) {
  92                        if (__vlan_insert_inner_tag(skb, skb->vlan_proto,
  93                                                    skb_vlan_tag_get(skb),
  94                                                    ETH_HLEN) < 0)
  95                                goto drop;
  96
  97                        skb->protocol = skb->vlan_proto;
  98                        __vlan_hwaccel_clear_tag(skb);
  99                }
 100
 101                new_lse = tcf_mpls_get_lse(NULL, p, mac_len ||
 102                                           !eth_p_mpls(skb->protocol));
 103
 104                if (skb_mpls_push(skb, new_lse, p->tcfm_proto, 0, false))
 105                        goto drop;
 106                break;
 107        case TCA_MPLS_ACT_MODIFY:
 108                if (!pskb_may_pull(skb,
 109                                   skb_network_offset(skb) + MPLS_HLEN))
 110                        goto drop;
 111                new_lse = tcf_mpls_get_lse(mpls_hdr(skb), p, false);
 112                if (skb_mpls_update_lse(skb, new_lse))
 113                        goto drop;
 114                break;
 115        case TCA_MPLS_ACT_DEC_TTL:
 116                if (skb_mpls_dec_ttl(skb))
 117                        goto drop;
 118                break;
 119        }
 120
 121        if (skb_at_tc_ingress(skb))
 122                skb_pull_rcsum(skb, skb->mac_len);
 123
 124        return ret;
 125
 126drop:
 127        qstats_drop_inc(this_cpu_ptr(m->common.cpu_qstats));
 128        return TC_ACT_SHOT;
 129}
 130
 131static int valid_label(const struct nlattr *attr,
 132                       struct netlink_ext_ack *extack)
 133{
 134        const u32 *label = nla_data(attr);
 135
 136        if (*label & ~MPLS_LABEL_MASK || *label == MPLS_LABEL_IMPLNULL) {
 137                NL_SET_ERR_MSG_MOD(extack, "MPLS label out of range");
 138                return -EINVAL;
 139        }
 140
 141        return 0;
 142}
 143
 144static const struct nla_policy mpls_policy[TCA_MPLS_MAX + 1] = {
 145        [TCA_MPLS_PARMS]        = NLA_POLICY_EXACT_LEN(sizeof(struct tc_mpls)),
 146        [TCA_MPLS_PROTO]        = { .type = NLA_U16 },
 147        [TCA_MPLS_LABEL]        = NLA_POLICY_VALIDATE_FN(NLA_U32, valid_label),
 148        [TCA_MPLS_TC]           = NLA_POLICY_RANGE(NLA_U8, 0, 7),
 149        [TCA_MPLS_TTL]          = NLA_POLICY_MIN(NLA_U8, 1),
 150        [TCA_MPLS_BOS]          = NLA_POLICY_RANGE(NLA_U8, 0, 1),
 151};
 152
 153static int tcf_mpls_init(struct net *net, struct nlattr *nla,
 154                         struct nlattr *est, struct tc_action **a,
 155                         int ovr, int bind, bool rtnl_held,
 156                         struct tcf_proto *tp, u32 flags,
 157                         struct netlink_ext_ack *extack)
 158{
 159        struct tc_action_net *tn = net_generic(net, mpls_net_id);
 160        struct nlattr *tb[TCA_MPLS_MAX + 1];
 161        struct tcf_chain *goto_ch = NULL;
 162        struct tcf_mpls_params *p;
 163        struct tc_mpls *parm;
 164        bool exists = false;
 165        struct tcf_mpls *m;
 166        int ret = 0, err;
 167        u8 mpls_ttl = 0;
 168        u32 index;
 169
 170        if (!nla) {
 171                NL_SET_ERR_MSG_MOD(extack, "Missing netlink attributes");
 172                return -EINVAL;
 173        }
 174
 175        err = nla_parse_nested(tb, TCA_MPLS_MAX, nla, mpls_policy, extack);
 176        if (err < 0)
 177                return err;
 178
 179        if (!tb[TCA_MPLS_PARMS]) {
 180                NL_SET_ERR_MSG_MOD(extack, "No MPLS params");
 181                return -EINVAL;
 182        }
 183        parm = nla_data(tb[TCA_MPLS_PARMS]);
 184        index = parm->index;
 185
 186        /* Verify parameters against action type. */
 187        switch (parm->m_action) {
 188        case TCA_MPLS_ACT_POP:
 189                if (!tb[TCA_MPLS_PROTO]) {
 190                        NL_SET_ERR_MSG_MOD(extack, "Protocol must be set for MPLS pop");
 191                        return -EINVAL;
 192                }
 193                if (!eth_proto_is_802_3(nla_get_be16(tb[TCA_MPLS_PROTO]))) {
 194                        NL_SET_ERR_MSG_MOD(extack, "Invalid protocol type for MPLS pop");
 195                        return -EINVAL;
 196                }
 197                if (tb[TCA_MPLS_LABEL] || tb[TCA_MPLS_TTL] || tb[TCA_MPLS_TC] ||
 198                    tb[TCA_MPLS_BOS]) {
 199                        NL_SET_ERR_MSG_MOD(extack, "Label, TTL, TC or BOS cannot be used with MPLS pop");
 200                        return -EINVAL;
 201                }
 202                break;
 203        case TCA_MPLS_ACT_DEC_TTL:
 204                if (tb[TCA_MPLS_PROTO] || tb[TCA_MPLS_LABEL] ||
 205                    tb[TCA_MPLS_TTL] || tb[TCA_MPLS_TC] || tb[TCA_MPLS_BOS]) {
 206                        NL_SET_ERR_MSG_MOD(extack, "Label, TTL, TC, BOS or protocol cannot be used with MPLS dec_ttl");
 207                        return -EINVAL;
 208                }
 209                break;
 210        case TCA_MPLS_ACT_PUSH:
 211        case TCA_MPLS_ACT_MAC_PUSH:
 212                if (!tb[TCA_MPLS_LABEL]) {
 213                        NL_SET_ERR_MSG_MOD(extack, "Label is required for MPLS push");
 214                        return -EINVAL;
 215                }
 216                if (tb[TCA_MPLS_PROTO] &&
 217                    !eth_p_mpls(nla_get_be16(tb[TCA_MPLS_PROTO]))) {
 218                        NL_SET_ERR_MSG_MOD(extack, "Protocol must be an MPLS type for MPLS push");
 219                        return -EPROTONOSUPPORT;
 220                }
 221                /* Push needs a TTL - if not specified, set a default value. */
 222                if (!tb[TCA_MPLS_TTL]) {
 223#if IS_ENABLED(CONFIG_MPLS)
 224                        mpls_ttl = net->mpls.default_ttl ?
 225                                   net->mpls.default_ttl : ACT_MPLS_TTL_DEFAULT;
 226#else
 227                        mpls_ttl = ACT_MPLS_TTL_DEFAULT;
 228#endif
 229                }
 230                break;
 231        case TCA_MPLS_ACT_MODIFY:
 232                if (tb[TCA_MPLS_PROTO]) {
 233                        NL_SET_ERR_MSG_MOD(extack, "Protocol cannot be used with MPLS modify");
 234                        return -EINVAL;
 235                }
 236                break;
 237        default:
 238                NL_SET_ERR_MSG_MOD(extack, "Unknown MPLS action");
 239                return -EINVAL;
 240        }
 241
 242        err = tcf_idr_check_alloc(tn, &index, a, bind);
 243        if (err < 0)
 244                return err;
 245        exists = err;
 246        if (exists && bind)
 247                return 0;
 248
 249        if (!exists) {
 250                ret = tcf_idr_create(tn, index, est, a,
 251                                     &act_mpls_ops, bind, true, 0);
 252                if (ret) {
 253                        tcf_idr_cleanup(tn, index);
 254                        return ret;
 255                }
 256
 257                ret = ACT_P_CREATED;
 258        } else if (!ovr) {
 259                tcf_idr_release(*a, bind);
 260                return -EEXIST;
 261        }
 262
 263        err = tcf_action_check_ctrlact(parm->action, tp, &goto_ch, extack);
 264        if (err < 0)
 265                goto release_idr;
 266
 267        m = to_mpls(*a);
 268
 269        p = kzalloc(sizeof(*p), GFP_KERNEL);
 270        if (!p) {
 271                err = -ENOMEM;
 272                goto put_chain;
 273        }
 274
 275        p->tcfm_action = parm->m_action;
 276        p->tcfm_label = tb[TCA_MPLS_LABEL] ? nla_get_u32(tb[TCA_MPLS_LABEL]) :
 277                                             ACT_MPLS_LABEL_NOT_SET;
 278        p->tcfm_tc = tb[TCA_MPLS_TC] ? nla_get_u8(tb[TCA_MPLS_TC]) :
 279                                       ACT_MPLS_TC_NOT_SET;
 280        p->tcfm_ttl = tb[TCA_MPLS_TTL] ? nla_get_u8(tb[TCA_MPLS_TTL]) :
 281                                         mpls_ttl;
 282        p->tcfm_bos = tb[TCA_MPLS_BOS] ? nla_get_u8(tb[TCA_MPLS_BOS]) :
 283                                         ACT_MPLS_BOS_NOT_SET;
 284        p->tcfm_proto = tb[TCA_MPLS_PROTO] ? nla_get_be16(tb[TCA_MPLS_PROTO]) :
 285                                             htons(ETH_P_MPLS_UC);
 286
 287        spin_lock_bh(&m->tcf_lock);
 288        goto_ch = tcf_action_set_ctrlact(*a, parm->action, goto_ch);
 289        p = rcu_replace_pointer(m->mpls_p, p, lockdep_is_held(&m->tcf_lock));
 290        spin_unlock_bh(&m->tcf_lock);
 291
 292        if (goto_ch)
 293                tcf_chain_put_by_act(goto_ch);
 294        if (p)
 295                kfree_rcu(p, rcu);
 296
 297        return ret;
 298put_chain:
 299        if (goto_ch)
 300                tcf_chain_put_by_act(goto_ch);
 301release_idr:
 302        tcf_idr_release(*a, bind);
 303        return err;
 304}
 305
 306static void tcf_mpls_cleanup(struct tc_action *a)
 307{
 308        struct tcf_mpls *m = to_mpls(a);
 309        struct tcf_mpls_params *p;
 310
 311        p = rcu_dereference_protected(m->mpls_p, 1);
 312        if (p)
 313                kfree_rcu(p, rcu);
 314}
 315
 316static int tcf_mpls_dump(struct sk_buff *skb, struct tc_action *a,
 317                         int bind, int ref)
 318{
 319        unsigned char *b = skb_tail_pointer(skb);
 320        struct tcf_mpls *m = to_mpls(a);
 321        struct tcf_mpls_params *p;
 322        struct tc_mpls opt = {
 323                .index    = m->tcf_index,
 324                .refcnt   = refcount_read(&m->tcf_refcnt) - ref,
 325                .bindcnt  = atomic_read(&m->tcf_bindcnt) - bind,
 326        };
 327        struct tcf_t t;
 328
 329        spin_lock_bh(&m->tcf_lock);
 330        opt.action = m->tcf_action;
 331        p = rcu_dereference_protected(m->mpls_p, lockdep_is_held(&m->tcf_lock));
 332        opt.m_action = p->tcfm_action;
 333
 334        if (nla_put(skb, TCA_MPLS_PARMS, sizeof(opt), &opt))
 335                goto nla_put_failure;
 336
 337        if (p->tcfm_label != ACT_MPLS_LABEL_NOT_SET &&
 338            nla_put_u32(skb, TCA_MPLS_LABEL, p->tcfm_label))
 339                goto nla_put_failure;
 340
 341        if (p->tcfm_tc != ACT_MPLS_TC_NOT_SET &&
 342            nla_put_u8(skb, TCA_MPLS_TC, p->tcfm_tc))
 343                goto nla_put_failure;
 344
 345        if (p->tcfm_ttl && nla_put_u8(skb, TCA_MPLS_TTL, p->tcfm_ttl))
 346                goto nla_put_failure;
 347
 348        if (p->tcfm_bos != ACT_MPLS_BOS_NOT_SET &&
 349            nla_put_u8(skb, TCA_MPLS_BOS, p->tcfm_bos))
 350                goto nla_put_failure;
 351
 352        if (nla_put_be16(skb, TCA_MPLS_PROTO, p->tcfm_proto))
 353                goto nla_put_failure;
 354
 355        tcf_tm_dump(&t, &m->tcf_tm);
 356
 357        if (nla_put_64bit(skb, TCA_MPLS_TM, sizeof(t), &t, TCA_MPLS_PAD))
 358                goto nla_put_failure;
 359
 360        spin_unlock_bh(&m->tcf_lock);
 361
 362        return skb->len;
 363
 364nla_put_failure:
 365        spin_unlock_bh(&m->tcf_lock);
 366        nlmsg_trim(skb, b);
 367        return -EMSGSIZE;
 368}
 369
 370static int tcf_mpls_walker(struct net *net, struct sk_buff *skb,
 371                           struct netlink_callback *cb, int type,
 372                           const struct tc_action_ops *ops,
 373                           struct netlink_ext_ack *extack)
 374{
 375        struct tc_action_net *tn = net_generic(net, mpls_net_id);
 376
 377        return tcf_generic_walker(tn, skb, cb, type, ops, extack);
 378}
 379
 380static int tcf_mpls_search(struct net *net, struct tc_action **a, u32 index)
 381{
 382        struct tc_action_net *tn = net_generic(net, mpls_net_id);
 383
 384        return tcf_idr_search(tn, a, index);
 385}
 386
 387static struct tc_action_ops act_mpls_ops = {
 388        .kind           =       "mpls",
 389        .id             =       TCA_ID_MPLS,
 390        .owner          =       THIS_MODULE,
 391        .act            =       tcf_mpls_act,
 392        .dump           =       tcf_mpls_dump,
 393        .init           =       tcf_mpls_init,
 394        .cleanup        =       tcf_mpls_cleanup,
 395        .walk           =       tcf_mpls_walker,
 396        .lookup         =       tcf_mpls_search,
 397        .size           =       sizeof(struct tcf_mpls),
 398};
 399
 400static __net_init int mpls_init_net(struct net *net)
 401{
 402        struct tc_action_net *tn = net_generic(net, mpls_net_id);
 403
 404        return tc_action_net_init(net, tn, &act_mpls_ops);
 405}
 406
 407static void __net_exit mpls_exit_net(struct list_head *net_list)
 408{
 409        tc_action_net_exit(net_list, mpls_net_id);
 410}
 411
 412static struct pernet_operations mpls_net_ops = {
 413        .init = mpls_init_net,
 414        .exit_batch = mpls_exit_net,
 415        .id   = &mpls_net_id,
 416        .size = sizeof(struct tc_action_net),
 417};
 418
 419static int __init mpls_init_module(void)
 420{
 421        return tcf_register_action(&act_mpls_ops, &mpls_net_ops);
 422}
 423
 424static void __exit mpls_cleanup_module(void)
 425{
 426        tcf_unregister_action(&act_mpls_ops, &mpls_net_ops);
 427}
 428
 429module_init(mpls_init_module);
 430module_exit(mpls_cleanup_module);
 431
 432MODULE_SOFTDEP("post: mpls_gso");
 433MODULE_AUTHOR("Netronome Systems <oss-drivers@netronome.com>");
 434MODULE_LICENSE("GPL");
 435MODULE_DESCRIPTION("MPLS manipulation actions");
 436