1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * net/sched/ife.c Inter-FE action based on ForCES WG InterFE LFB 4 * 5 * Refer to: 6 * draft-ietf-forces-interfelfb-03 7 * and 8 * netdev01 paper: 9 * "Distributing Linux Traffic Control Classifier-Action 10 * Subsystem" 11 * Authors: Jamal Hadi Salim and Damascene M. Joachimpillai 12 * 13 * copyright Jamal Hadi Salim (2015) 14 */ 15 16 #include <linux/types.h> 17 #include <linux/kernel.h> 18 #include <linux/string.h> 19 #include <linux/errno.h> 20 #include <linux/skbuff.h> 21 #include <linux/rtnetlink.h> 22 #include <linux/module.h> 23 #include <linux/init.h> 24 #include <net/net_namespace.h> 25 #include <net/netlink.h> 26 #include <net/pkt_sched.h> 27 #include <net/pkt_cls.h> 28 #include <uapi/linux/tc_act/tc_ife.h> 29 #include <net/tc_act/tc_ife.h> 30 #include <linux/etherdevice.h> 31 #include <net/ife.h> 32 #include <net/tc_wrapper.h> 33 34 static int max_metacnt = IFE_META_MAX + 1; 35 static struct tc_action_ops act_ife_ops; 36 37 static const struct nla_policy ife_policy[TCA_IFE_MAX + 1] = { 38 [TCA_IFE_PARMS] = { .len = sizeof(struct tc_ife)}, 39 [TCA_IFE_DMAC] = { .len = ETH_ALEN}, 40 [TCA_IFE_SMAC] = { .len = ETH_ALEN}, 41 [TCA_IFE_TYPE] = { .type = NLA_U16}, 42 }; 43 44 int ife_encode_meta_u16(u16 metaval, void *skbdata, struct tcf_meta_info *mi) 45 { 46 u16 edata = 0; 47 48 if (mi->metaval) 49 edata = *(u16 *)mi->metaval; 50 else if (metaval) 51 edata = metaval; 52 53 if (!edata) /* will not encode */ 54 return 0; 55 56 edata = htons(edata); 57 return ife_tlv_meta_encode(skbdata, mi->metaid, 2, &edata); 58 } 59 EXPORT_SYMBOL_GPL(ife_encode_meta_u16); 60 61 int ife_get_meta_u32(struct sk_buff *skb, struct tcf_meta_info *mi) 62 { 63 if (mi->metaval) 64 return nla_put_u32(skb, mi->metaid, *(u32 *)mi->metaval); 65 else 66 return nla_put(skb, mi->metaid, 0, NULL); 67 } 68 EXPORT_SYMBOL_GPL(ife_get_meta_u32); 69 70 int ife_check_meta_u32(u32 metaval, struct tcf_meta_info *mi) 71 { 72 if (metaval || mi->metaval) 73 return 8; /* T+L+V == 2+2+4 */ 74 75 return 0; 76 } 77 EXPORT_SYMBOL_GPL(ife_check_meta_u32); 78 79 int ife_check_meta_u16(u16 metaval, struct tcf_meta_info *mi) 80 { 81 if (metaval || mi->metaval) 82 return 8; /* T+L+(V) == 2+2+(2+2bytepad) */ 83 84 return 0; 85 } 86 EXPORT_SYMBOL_GPL(ife_check_meta_u16); 87 88 int ife_encode_meta_u32(u32 metaval, void *skbdata, struct tcf_meta_info *mi) 89 { 90 u32 edata = metaval; 91 92 if (mi->metaval) 93 edata = *(u32 *)mi->metaval; 94 else if (metaval) 95 edata = metaval; 96 97 if (!edata) /* will not encode */ 98 return 0; 99 100 edata = htonl(edata); 101 return ife_tlv_meta_encode(skbdata, mi->metaid, 4, &edata); 102 } 103 EXPORT_SYMBOL_GPL(ife_encode_meta_u32); 104 105 int ife_get_meta_u16(struct sk_buff *skb, struct tcf_meta_info *mi) 106 { 107 if (mi->metaval) 108 return nla_put_u16(skb, mi->metaid, *(u16 *)mi->metaval); 109 else 110 return nla_put(skb, mi->metaid, 0, NULL); 111 } 112 EXPORT_SYMBOL_GPL(ife_get_meta_u16); 113 114 int ife_alloc_meta_u32(struct tcf_meta_info *mi, void *metaval, gfp_t gfp) 115 { 116 mi->metaval = kmemdup(metaval, sizeof(u32), gfp); 117 if (!mi->metaval) 118 return -ENOMEM; 119 120 return 0; 121 } 122 EXPORT_SYMBOL_GPL(ife_alloc_meta_u32); 123 124 int ife_alloc_meta_u16(struct tcf_meta_info *mi, void *metaval, gfp_t gfp) 125 { 126 mi->metaval = kmemdup(metaval, sizeof(u16), gfp); 127 if (!mi->metaval) 128 return -ENOMEM; 129 130 return 0; 131 } 132 EXPORT_SYMBOL_GPL(ife_alloc_meta_u16); 133 134 void ife_release_meta_gen(struct tcf_meta_info *mi) 135 { 136 kfree(mi->metaval); 137 } 138 EXPORT_SYMBOL_GPL(ife_release_meta_gen); 139 140 int ife_validate_meta_u32(void *val, int len) 141 { 142 if (len == sizeof(u32)) 143 return 0; 144 145 return -EINVAL; 146 } 147 EXPORT_SYMBOL_GPL(ife_validate_meta_u32); 148 149 int ife_validate_meta_u16(void *val, int len) 150 { 151 /* length will not include padding */ 152 if (len == sizeof(u16)) 153 return 0; 154 155 return -EINVAL; 156 } 157 EXPORT_SYMBOL_GPL(ife_validate_meta_u16); 158 159 static LIST_HEAD(ifeoplist); 160 static DEFINE_RWLOCK(ife_mod_lock); 161 162 static struct tcf_meta_ops *find_ife_oplist(u16 metaid) 163 { 164 struct tcf_meta_ops *o; 165 166 read_lock(&ife_mod_lock); 167 list_for_each_entry(o, &ifeoplist, list) { 168 if (o->metaid == metaid) { 169 if (!try_module_get(o->owner)) 170 o = NULL; 171 read_unlock(&ife_mod_lock); 172 return o; 173 } 174 } 175 read_unlock(&ife_mod_lock); 176 177 return NULL; 178 } 179 180 int register_ife_op(struct tcf_meta_ops *mops) 181 { 182 struct tcf_meta_ops *m; 183 184 if (!mops->metaid || !mops->metatype || !mops->name || 185 !mops->check_presence || !mops->encode || !mops->decode || 186 !mops->get || !mops->alloc) 187 return -EINVAL; 188 189 write_lock(&ife_mod_lock); 190 191 list_for_each_entry(m, &ifeoplist, list) { 192 if (m->metaid == mops->metaid || 193 (strcmp(mops->name, m->name) == 0)) { 194 write_unlock(&ife_mod_lock); 195 return -EEXIST; 196 } 197 } 198 199 if (!mops->release) 200 mops->release = ife_release_meta_gen; 201 202 list_add_tail(&mops->list, &ifeoplist); 203 write_unlock(&ife_mod_lock); 204 return 0; 205 } 206 EXPORT_SYMBOL_GPL(unregister_ife_op); 207 208 int unregister_ife_op(struct tcf_meta_ops *mops) 209 { 210 struct tcf_meta_ops *m; 211 int err = -ENOENT; 212 213 write_lock(&ife_mod_lock); 214 list_for_each_entry(m, &ifeoplist, list) { 215 if (m->metaid == mops->metaid) { 216 list_del(&mops->list); 217 err = 0; 218 break; 219 } 220 } 221 write_unlock(&ife_mod_lock); 222 223 return err; 224 } 225 EXPORT_SYMBOL_GPL(register_ife_op); 226 227 static int ife_validate_metatype(struct tcf_meta_ops *ops, void *val, int len) 228 { 229 int ret = 0; 230 /* XXX: unfortunately cant use nla_policy at this point 231 * because a length of 0 is valid in the case of 232 * "allow". "use" semantics do enforce for proper 233 * length and i couldve use nla_policy but it makes it hard 234 * to use it just for that.. 235 */ 236 if (ops->validate) 237 return ops->validate(val, len); 238 239 if (ops->metatype == NLA_U32) 240 ret = ife_validate_meta_u32(val, len); 241 else if (ops->metatype == NLA_U16) 242 ret = ife_validate_meta_u16(val, len); 243 244 return ret; 245 } 246 247 #ifdef CONFIG_MODULES 248 static const char *ife_meta_id2name(u32 metaid) 249 { 250 switch (metaid) { 251 case IFE_META_SKBMARK: 252 return "skbmark"; 253 case IFE_META_PRIO: 254 return "skbprio"; 255 case IFE_META_TCINDEX: 256 return "tcindex"; 257 default: 258 return "unknown"; 259 } 260 } 261 #endif 262 263 /* called when adding new meta information 264 */ 265 static int load_metaops_and_vet(u32 metaid, void *val, int len, bool rtnl_held) 266 { 267 struct tcf_meta_ops *ops = find_ife_oplist(metaid); 268 int ret = 0; 269 270 if (!ops) { 271 ret = -ENOENT; 272 #ifdef CONFIG_MODULES 273 if (rtnl_held) 274 rtnl_unlock(); 275 request_module("ife-meta-%s", ife_meta_id2name(metaid)); 276 if (rtnl_held) 277 rtnl_lock(); 278 ops = find_ife_oplist(metaid); 279 #endif 280 } 281 282 if (ops) { 283 ret = 0; 284 if (len) 285 ret = ife_validate_metatype(ops, val, len); 286 287 module_put(ops->owner); 288 } 289 290 return ret; 291 } 292 293 /* called when adding new meta information 294 */ 295 static int __add_metainfo(const struct tcf_meta_ops *ops, 296 struct tcf_ife_params *p, u32 metaid, void *metaval, 297 int len, bool atomic) 298 { 299 struct tcf_meta_info *mi = NULL; 300 int ret = 0; 301 302 mi = kzalloc_obj(*mi, atomic ? GFP_ATOMIC : GFP_KERNEL); 303 if (!mi) 304 return -ENOMEM; 305 306 mi->metaid = metaid; 307 mi->ops = ops; 308 if (len > 0) { 309 ret = ops->alloc(mi, metaval, atomic ? GFP_ATOMIC : GFP_KERNEL); 310 if (ret != 0) { 311 kfree(mi); 312 return ret; 313 } 314 } 315 316 list_add_tail(&mi->metalist, &p->metalist); 317 318 return ret; 319 } 320 321 static int add_metainfo_and_get_ops(const struct tcf_meta_ops *ops, 322 struct tcf_ife_params *p, u32 metaid) 323 { 324 int ret; 325 326 if (!try_module_get(ops->owner)) 327 return -ENOENT; 328 ret = __add_metainfo(ops, p, metaid, NULL, 0, true); 329 if (ret) 330 module_put(ops->owner); 331 return ret; 332 } 333 334 static int add_metainfo(struct tcf_ife_params *p, u32 metaid, void *metaval, 335 int len) 336 { 337 const struct tcf_meta_ops *ops = find_ife_oplist(metaid); 338 int ret; 339 340 if (!ops) 341 return -ENOENT; 342 ret = __add_metainfo(ops, p, metaid, metaval, len, false); 343 if (ret) 344 /*put back what find_ife_oplist took */ 345 module_put(ops->owner); 346 return ret; 347 } 348 349 static int use_all_metadata(struct tcf_ife_params *p) 350 { 351 struct tcf_meta_ops *o; 352 int rc = 0; 353 int installed = 0; 354 355 read_lock(&ife_mod_lock); 356 list_for_each_entry(o, &ifeoplist, list) { 357 rc = add_metainfo_and_get_ops(o, p, o->metaid); 358 if (rc == 0) 359 installed += 1; 360 } 361 read_unlock(&ife_mod_lock); 362 363 if (installed) 364 return 0; 365 else 366 return -EINVAL; 367 } 368 369 static int dump_metalist(struct sk_buff *skb, struct tcf_ife_params *p) 370 { 371 struct tcf_meta_info *e; 372 struct nlattr *nest; 373 unsigned char *b = skb_tail_pointer(skb); 374 int total_encoded = 0; 375 376 /*can only happen on decode */ 377 if (list_empty(&p->metalist)) 378 return 0; 379 380 nest = nla_nest_start_noflag(skb, TCA_IFE_METALST); 381 if (!nest) 382 goto out_nlmsg_trim; 383 384 list_for_each_entry(e, &p->metalist, metalist) { 385 if (!e->ops->get(skb, e)) 386 total_encoded += 1; 387 } 388 389 if (!total_encoded) 390 goto out_nlmsg_trim; 391 392 nla_nest_end(skb, nest); 393 394 return 0; 395 396 out_nlmsg_trim: 397 nlmsg_trim(skb, b); 398 return -1; 399 } 400 401 static void __tcf_ife_cleanup(struct tcf_ife_params *p) 402 { 403 struct tcf_meta_info *e, *n; 404 405 list_for_each_entry_safe(e, n, &p->metalist, metalist) { 406 list_del(&e->metalist); 407 if (e->metaval) { 408 if (e->ops->release) 409 e->ops->release(e); 410 else 411 kfree(e->metaval); 412 } 413 module_put(e->ops->owner); 414 kfree(e); 415 } 416 } 417 418 static void tcf_ife_cleanup_params(struct rcu_head *head) 419 { 420 struct tcf_ife_params *p = container_of(head, struct tcf_ife_params, 421 rcu); 422 423 __tcf_ife_cleanup(p); 424 kfree(p); 425 } 426 427 static void tcf_ife_cleanup(struct tc_action *a) 428 { 429 struct tcf_ife_info *ife = to_ife(a); 430 struct tcf_ife_params *p; 431 432 p = rcu_dereference_protected(ife->params, 1); 433 if (p) 434 call_rcu(&p->rcu, tcf_ife_cleanup_params); 435 } 436 437 static int load_metalist(struct nlattr **tb, bool rtnl_held) 438 { 439 int i; 440 441 for (i = 1; i < max_metacnt; i++) { 442 if (tb[i]) { 443 void *val = nla_data(tb[i]); 444 int len = nla_len(tb[i]); 445 int rc; 446 447 rc = load_metaops_and_vet(i, val, len, rtnl_held); 448 if (rc != 0) 449 return rc; 450 } 451 } 452 453 return 0; 454 } 455 456 static int populate_metalist(struct tcf_ife_params *p, struct nlattr **tb) 457 { 458 int len = 0; 459 int rc = 0; 460 int i = 0; 461 void *val; 462 463 for (i = 1; i < max_metacnt; i++) { 464 if (tb[i]) { 465 val = nla_data(tb[i]); 466 len = nla_len(tb[i]); 467 468 rc = add_metainfo(p, i, val, len); 469 if (rc) 470 return rc; 471 } 472 } 473 474 return rc; 475 } 476 477 static int tcf_ife_init(struct net *net, struct nlattr *nla, 478 struct nlattr *est, struct tc_action **a, 479 struct tcf_proto *tp, u32 flags, 480 struct netlink_ext_ack *extack) 481 { 482 struct tc_action_net *tn = net_generic(net, act_ife_ops.net_id); 483 bool bind = flags & TCA_ACT_FLAGS_BIND; 484 struct nlattr *tb[TCA_IFE_MAX + 1]; 485 struct nlattr *tb2[IFE_META_MAX + 1]; 486 struct tcf_chain *goto_ch = NULL; 487 struct tcf_ife_params *p; 488 struct tcf_ife_info *ife; 489 u16 ife_type = ETH_P_IFE; 490 struct tc_ife *parm; 491 u8 *daddr = NULL; 492 u8 *saddr = NULL; 493 bool exists = false; 494 int ret = 0; 495 u32 index; 496 int err; 497 498 if (!nla) { 499 NL_SET_ERR_MSG_MOD(extack, "IFE requires attributes to be passed"); 500 return -EINVAL; 501 } 502 503 err = nla_parse_nested_deprecated(tb, TCA_IFE_MAX, nla, ife_policy, 504 NULL); 505 if (err < 0) 506 return err; 507 508 if (!tb[TCA_IFE_PARMS]) 509 return -EINVAL; 510 511 parm = nla_data(tb[TCA_IFE_PARMS]); 512 513 /* IFE_DECODE is 0 and indicates the opposite of IFE_ENCODE because 514 * they cannot run as the same time. Check on all other values which 515 * are not supported right now. 516 */ 517 if (parm->flags & ~IFE_ENCODE) 518 return -EINVAL; 519 520 p = kzalloc_obj(*p); 521 if (!p) 522 return -ENOMEM; 523 INIT_LIST_HEAD(&p->metalist); 524 525 if (tb[TCA_IFE_METALST]) { 526 err = nla_parse_nested_deprecated(tb2, IFE_META_MAX, 527 tb[TCA_IFE_METALST], NULL, 528 NULL); 529 if (err) { 530 kfree(p); 531 return err; 532 } 533 err = load_metalist(tb2, !(flags & TCA_ACT_FLAGS_NO_RTNL)); 534 if (err) { 535 kfree(p); 536 return err; 537 } 538 } 539 540 index = parm->index; 541 err = tcf_idr_check_alloc(tn, &index, a, bind); 542 if (err < 0) { 543 kfree(p); 544 return err; 545 } 546 exists = err; 547 if (exists && bind) { 548 kfree(p); 549 return ACT_P_BOUND; 550 } 551 552 if (!exists) { 553 ret = tcf_idr_create(tn, index, est, a, &act_ife_ops, 554 bind, true, flags); 555 if (ret) { 556 tcf_idr_cleanup(tn, index); 557 kfree(p); 558 return ret; 559 } 560 ret = ACT_P_CREATED; 561 } else if (!(flags & TCA_ACT_FLAGS_REPLACE)) { 562 tcf_idr_release(*a, bind); 563 kfree(p); 564 return -EEXIST; 565 } 566 567 ife = to_ife(*a); 568 569 err = tcf_action_check_ctrlact(parm->action, tp, &goto_ch, extack); 570 if (err < 0) 571 goto release_idr; 572 573 p->flags = parm->flags; 574 575 if (parm->flags & IFE_ENCODE) { 576 if (tb[TCA_IFE_TYPE]) 577 ife_type = nla_get_u16(tb[TCA_IFE_TYPE]); 578 if (tb[TCA_IFE_DMAC]) 579 daddr = nla_data(tb[TCA_IFE_DMAC]); 580 if (tb[TCA_IFE_SMAC]) 581 saddr = nla_data(tb[TCA_IFE_SMAC]); 582 } 583 584 if (parm->flags & IFE_ENCODE) { 585 if (daddr) 586 ether_addr_copy(p->eth_dst, daddr); 587 else 588 eth_zero_addr(p->eth_dst); 589 590 if (saddr) 591 ether_addr_copy(p->eth_src, saddr); 592 else 593 eth_zero_addr(p->eth_src); 594 595 p->eth_type = ife_type; 596 } 597 598 if (tb[TCA_IFE_METALST]) { 599 err = populate_metalist(p, tb2); 600 if (err) 601 goto metadata_parse_err; 602 } else { 603 /* if no passed metadata allow list or passed allow-all 604 * then here we process by adding as many supported metadatum 605 * as we can. You better have at least one else we are 606 * going to bail out 607 */ 608 err = use_all_metadata(p); 609 if (err) 610 goto metadata_parse_err; 611 } 612 613 if (exists) 614 spin_lock_bh(&ife->tcf_lock); 615 /* protected by tcf_lock when modifying existing action */ 616 goto_ch = tcf_action_set_ctrlact(*a, parm->action, goto_ch); 617 p = rcu_replace_pointer(ife->params, p, 1); 618 619 if (exists) 620 spin_unlock_bh(&ife->tcf_lock); 621 if (goto_ch) 622 tcf_chain_put_by_act(goto_ch); 623 if (p) 624 call_rcu(&p->rcu, tcf_ife_cleanup_params); 625 626 return ret; 627 metadata_parse_err: 628 if (goto_ch) 629 tcf_chain_put_by_act(goto_ch); 630 release_idr: 631 __tcf_ife_cleanup(p); 632 kfree(p); 633 tcf_idr_release(*a, bind); 634 return err; 635 } 636 637 static int tcf_ife_dump(struct sk_buff *skb, struct tc_action *a, int bind, 638 int ref) 639 { 640 unsigned char *b = skb_tail_pointer(skb); 641 struct tcf_ife_info *ife = to_ife(a); 642 struct tcf_ife_params *p; 643 struct tc_ife opt; 644 struct tcf_t t; 645 646 memset(&opt, 0, sizeof(opt)); 647 648 opt.index = ife->tcf_index; 649 opt.refcnt = refcount_read(&ife->tcf_refcnt) - ref; 650 opt.bindcnt = atomic_read(&ife->tcf_bindcnt) - bind; 651 652 spin_lock_bh(&ife->tcf_lock); 653 opt.action = ife->tcf_action; 654 p = rcu_dereference_protected(ife->params, 655 lockdep_is_held(&ife->tcf_lock)); 656 opt.flags = p->flags; 657 658 if (nla_put(skb, TCA_IFE_PARMS, sizeof(opt), &opt)) 659 goto nla_put_failure; 660 661 tcf_tm_dump(&t, &ife->tcf_tm); 662 if (nla_put_64bit(skb, TCA_IFE_TM, sizeof(t), &t, TCA_IFE_PAD)) 663 goto nla_put_failure; 664 665 if (!is_zero_ether_addr(p->eth_dst)) { 666 if (nla_put(skb, TCA_IFE_DMAC, ETH_ALEN, p->eth_dst)) 667 goto nla_put_failure; 668 } 669 670 if (!is_zero_ether_addr(p->eth_src)) { 671 if (nla_put(skb, TCA_IFE_SMAC, ETH_ALEN, p->eth_src)) 672 goto nla_put_failure; 673 } 674 675 if (nla_put(skb, TCA_IFE_TYPE, 2, &p->eth_type)) 676 goto nla_put_failure; 677 678 if (dump_metalist(skb, p)) { 679 /*ignore failure to dump metalist */ 680 pr_info("Failed to dump metalist\n"); 681 } 682 683 spin_unlock_bh(&ife->tcf_lock); 684 return skb->len; 685 686 nla_put_failure: 687 spin_unlock_bh(&ife->tcf_lock); 688 nlmsg_trim(skb, b); 689 return -1; 690 } 691 692 static int find_decode_metaid(struct sk_buff *skb, struct tcf_ife_params *p, 693 u16 metaid, u16 mlen, void *mdata) 694 { 695 struct tcf_meta_info *e; 696 697 /* XXX: use hash to speed up */ 698 list_for_each_entry_rcu(e, &p->metalist, metalist) { 699 if (metaid == e->metaid) { 700 if (e->ops) { 701 /* We check for decode presence already */ 702 return e->ops->decode(skb, mdata, mlen); 703 } 704 } 705 } 706 707 return -ENOENT; 708 } 709 710 static int tcf_ife_decode(struct sk_buff *skb, const struct tc_action *a, 711 struct tcf_result *res) 712 { 713 struct tcf_ife_info *ife = to_ife(a); 714 int action = ife->tcf_action; 715 struct tcf_ife_params *p; 716 u8 *ifehdr_end; 717 u8 *tlv_data; 718 u16 metalen; 719 720 p = rcu_dereference_bh(ife->params); 721 722 bstats_update(this_cpu_ptr(ife->common.cpu_bstats), skb); 723 tcf_lastuse_update(&ife->tcf_tm); 724 725 if (skb_at_tc_ingress(skb)) 726 skb_push(skb, skb->dev->hard_header_len); 727 728 tlv_data = ife_decode(skb, &metalen); 729 if (unlikely(!tlv_data)) { 730 qstats_drop_inc(this_cpu_ptr(ife->common.cpu_qstats)); 731 return TC_ACT_SHOT; 732 } 733 734 ifehdr_end = tlv_data + metalen; 735 for (; tlv_data < ifehdr_end; tlv_data = ife_tlv_meta_next(tlv_data)) { 736 u8 *curr_data; 737 u16 mtype; 738 u16 dlen; 739 740 curr_data = ife_tlv_meta_decode(tlv_data, ifehdr_end, &mtype, 741 &dlen, NULL); 742 if (!curr_data) { 743 qstats_drop_inc(this_cpu_ptr(ife->common.cpu_qstats)); 744 return TC_ACT_SHOT; 745 } 746 747 if (find_decode_metaid(skb, p, mtype, dlen, curr_data)) { 748 /* abuse overlimits to count when we receive metadata 749 * but dont have an ops for it 750 */ 751 pr_info_ratelimited("Unknown metaid %d dlen %d\n", 752 mtype, dlen); 753 qstats_overlimit_inc(this_cpu_ptr(ife->common.cpu_qstats)); 754 } 755 } 756 757 if (WARN_ON(tlv_data != ifehdr_end)) { 758 qstats_drop_inc(this_cpu_ptr(ife->common.cpu_qstats)); 759 return TC_ACT_SHOT; 760 } 761 762 skb->protocol = eth_type_trans(skb, skb->dev); 763 skb_reset_network_header(skb); 764 765 return action; 766 } 767 768 /*XXX: check if we can do this at install time instead of current 769 * send data path 770 **/ 771 static int ife_get_sz(struct sk_buff *skb, struct tcf_ife_params *p) 772 { 773 struct tcf_meta_info *e; 774 int tot_run_sz = 0, run_sz = 0; 775 776 list_for_each_entry_rcu(e, &p->metalist, metalist) { 777 if (e->ops->check_presence) { 778 run_sz = e->ops->check_presence(skb, e); 779 tot_run_sz += run_sz; 780 } 781 } 782 783 return tot_run_sz; 784 } 785 786 static int tcf_ife_encode(struct sk_buff *skb, const struct tc_action *a, 787 struct tcf_result *res, struct tcf_ife_params *p) 788 { 789 struct tcf_ife_info *ife = to_ife(a); 790 int action = ife->tcf_action; 791 struct ethhdr *oethh; /* outer ether header */ 792 struct tcf_meta_info *e; 793 /* 794 OUTERHDR:TOTMETALEN:{TLVHDR:Metadatum:TLVHDR..}:ORIGDATA 795 where ORIGDATA = original ethernet header ... 796 */ 797 u16 metalen = ife_get_sz(skb, p); 798 int hdrm = metalen + skb->dev->hard_header_len + IFE_METAHDRLEN; 799 unsigned int skboff = 0; 800 int new_len = skb->len + hdrm; 801 bool exceed_mtu = false; 802 void *ife_meta; 803 int err = 0; 804 805 if (!skb_at_tc_ingress(skb)) { 806 if (new_len > skb->dev->mtu) 807 exceed_mtu = true; 808 } 809 810 bstats_update(this_cpu_ptr(ife->common.cpu_bstats), skb); 811 tcf_lastuse_update(&ife->tcf_tm); 812 813 if (!metalen) { /* no metadata to send */ 814 /* abuse overlimits to count when we allow packet 815 * with no metadata 816 */ 817 qstats_overlimit_inc(this_cpu_ptr(ife->common.cpu_qstats)); 818 return action; 819 } 820 /* could be stupid policy setup or mtu config 821 * so lets be conservative.. */ 822 if ((action == TC_ACT_SHOT) || exceed_mtu) { 823 drop: 824 qstats_drop_inc(this_cpu_ptr(ife->common.cpu_qstats)); 825 return TC_ACT_SHOT; 826 } 827 828 if (skb_at_tc_ingress(skb)) 829 skb_push(skb, skb->dev->hard_header_len); 830 831 ife_meta = ife_encode(skb, metalen); 832 if (!ife_meta) 833 goto drop; 834 835 /* XXX: we dont have a clever way of telling encode to 836 * not repeat some of the computations that are done by 837 * ops->presence_check... 838 */ 839 list_for_each_entry_rcu(e, &p->metalist, metalist) { 840 if (e->ops->encode) { 841 err = e->ops->encode(skb, (void *)(ife_meta + skboff), 842 e); 843 } 844 if (err < 0) { 845 /* too corrupt to keep around if overwritten */ 846 goto drop; 847 } 848 skboff += err; 849 } 850 oethh = (struct ethhdr *)skb->data; 851 852 if (!is_zero_ether_addr(p->eth_src)) 853 ether_addr_copy(oethh->h_source, p->eth_src); 854 if (!is_zero_ether_addr(p->eth_dst)) 855 ether_addr_copy(oethh->h_dest, p->eth_dst); 856 oethh->h_proto = htons(p->eth_type); 857 858 if (skb_at_tc_ingress(skb)) 859 skb_pull(skb, skb->dev->hard_header_len); 860 861 return action; 862 } 863 864 TC_INDIRECT_SCOPE int tcf_ife_act(struct sk_buff *skb, 865 const struct tc_action *a, 866 struct tcf_result *res) 867 { 868 struct tcf_ife_info *ife = to_ife(a); 869 struct tcf_ife_params *p; 870 int ret; 871 872 p = rcu_dereference_bh(ife->params); 873 if (p->flags & IFE_ENCODE) { 874 ret = tcf_ife_encode(skb, a, res, p); 875 return ret; 876 } 877 878 return tcf_ife_decode(skb, a, res); 879 } 880 881 static struct tc_action_ops act_ife_ops = { 882 .kind = "ife", 883 .id = TCA_ID_IFE, 884 .owner = THIS_MODULE, 885 .act = tcf_ife_act, 886 .dump = tcf_ife_dump, 887 .cleanup = tcf_ife_cleanup, 888 .init = tcf_ife_init, 889 .size = sizeof(struct tcf_ife_info), 890 }; 891 MODULE_ALIAS_NET_ACT("ife"); 892 893 static __net_init int ife_init_net(struct net *net) 894 { 895 struct tc_action_net *tn = net_generic(net, act_ife_ops.net_id); 896 897 return tc_action_net_init(net, tn, &act_ife_ops); 898 } 899 900 static void __net_exit ife_exit_net(struct list_head *net_list) 901 { 902 tc_action_net_exit(net_list, act_ife_ops.net_id); 903 } 904 905 static struct pernet_operations ife_net_ops = { 906 .init = ife_init_net, 907 .exit_batch = ife_exit_net, 908 .id = &act_ife_ops.net_id, 909 .size = sizeof(struct tc_action_net), 910 }; 911 912 static int __init ife_init_module(void) 913 { 914 return tcf_register_action(&act_ife_ops, &ife_net_ops); 915 } 916 917 static void __exit ife_cleanup_module(void) 918 { 919 tcf_unregister_action(&act_ife_ops, &ife_net_ops); 920 } 921 922 module_init(ife_init_module); 923 module_exit(ife_cleanup_module); 924 925 MODULE_AUTHOR("Jamal Hadi Salim(2015)"); 926 MODULE_DESCRIPTION("Inter-FE LFB action"); 927 MODULE_LICENSE("GPL"); 928