act_ife.c (21379B)
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 33static unsigned int ife_net_id; 34static int max_metacnt = IFE_META_MAX + 1; 35static struct tc_action_ops act_ife_ops; 36 37static 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 44int 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} 59EXPORT_SYMBOL_GPL(ife_encode_meta_u16); 60 61int 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} 68EXPORT_SYMBOL_GPL(ife_get_meta_u32); 69 70int 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} 77EXPORT_SYMBOL_GPL(ife_check_meta_u32); 78 79int 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} 86EXPORT_SYMBOL_GPL(ife_check_meta_u16); 87 88int 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} 103EXPORT_SYMBOL_GPL(ife_encode_meta_u32); 104 105int 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} 112EXPORT_SYMBOL_GPL(ife_get_meta_u16); 113 114int 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} 122EXPORT_SYMBOL_GPL(ife_alloc_meta_u32); 123 124int 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} 132EXPORT_SYMBOL_GPL(ife_alloc_meta_u16); 133 134void ife_release_meta_gen(struct tcf_meta_info *mi) 135{ 136 kfree(mi->metaval); 137} 138EXPORT_SYMBOL_GPL(ife_release_meta_gen); 139 140int ife_validate_meta_u32(void *val, int len) 141{ 142 if (len == sizeof(u32)) 143 return 0; 144 145 return -EINVAL; 146} 147EXPORT_SYMBOL_GPL(ife_validate_meta_u32); 148 149int 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} 157EXPORT_SYMBOL_GPL(ife_validate_meta_u16); 158 159static LIST_HEAD(ifeoplist); 160static DEFINE_RWLOCK(ife_mod_lock); 161 162static 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 180int 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} 206EXPORT_SYMBOL_GPL(unregister_ife_op); 207 208int 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} 225EXPORT_SYMBOL_GPL(register_ife_op); 226 227static 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 248static 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*/ 265static 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*/ 295static int __add_metainfo(const struct tcf_meta_ops *ops, 296 struct tcf_ife_info *ife, u32 metaid, void *metaval, 297 int len, bool atomic, bool exists) 298{ 299 struct tcf_meta_info *mi = NULL; 300 int ret = 0; 301 302 mi = kzalloc(sizeof(*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 if (exists) 317 spin_lock_bh(&ife->tcf_lock); 318 list_add_tail(&mi->metalist, &ife->metalist); 319 if (exists) 320 spin_unlock_bh(&ife->tcf_lock); 321 322 return ret; 323} 324 325static int add_metainfo_and_get_ops(const struct tcf_meta_ops *ops, 326 struct tcf_ife_info *ife, u32 metaid, 327 bool exists) 328{ 329 int ret; 330 331 if (!try_module_get(ops->owner)) 332 return -ENOENT; 333 ret = __add_metainfo(ops, ife, metaid, NULL, 0, true, exists); 334 if (ret) 335 module_put(ops->owner); 336 return ret; 337} 338 339static int add_metainfo(struct tcf_ife_info *ife, u32 metaid, void *metaval, 340 int len, bool exists) 341{ 342 const struct tcf_meta_ops *ops = find_ife_oplist(metaid); 343 int ret; 344 345 if (!ops) 346 return -ENOENT; 347 ret = __add_metainfo(ops, ife, metaid, metaval, len, false, exists); 348 if (ret) 349 /*put back what find_ife_oplist took */ 350 module_put(ops->owner); 351 return ret; 352} 353 354static int use_all_metadata(struct tcf_ife_info *ife, bool exists) 355{ 356 struct tcf_meta_ops *o; 357 int rc = 0; 358 int installed = 0; 359 360 read_lock(&ife_mod_lock); 361 list_for_each_entry(o, &ifeoplist, list) { 362 rc = add_metainfo_and_get_ops(o, ife, o->metaid, exists); 363 if (rc == 0) 364 installed += 1; 365 } 366 read_unlock(&ife_mod_lock); 367 368 if (installed) 369 return 0; 370 else 371 return -EINVAL; 372} 373 374static int dump_metalist(struct sk_buff *skb, struct tcf_ife_info *ife) 375{ 376 struct tcf_meta_info *e; 377 struct nlattr *nest; 378 unsigned char *b = skb_tail_pointer(skb); 379 int total_encoded = 0; 380 381 /*can only happen on decode */ 382 if (list_empty(&ife->metalist)) 383 return 0; 384 385 nest = nla_nest_start_noflag(skb, TCA_IFE_METALST); 386 if (!nest) 387 goto out_nlmsg_trim; 388 389 list_for_each_entry(e, &ife->metalist, metalist) { 390 if (!e->ops->get(skb, e)) 391 total_encoded += 1; 392 } 393 394 if (!total_encoded) 395 goto out_nlmsg_trim; 396 397 nla_nest_end(skb, nest); 398 399 return 0; 400 401out_nlmsg_trim: 402 nlmsg_trim(skb, b); 403 return -1; 404} 405 406/* under ife->tcf_lock */ 407static void _tcf_ife_cleanup(struct tc_action *a) 408{ 409 struct tcf_ife_info *ife = to_ife(a); 410 struct tcf_meta_info *e, *n; 411 412 list_for_each_entry_safe(e, n, &ife->metalist, metalist) { 413 list_del(&e->metalist); 414 if (e->metaval) { 415 if (e->ops->release) 416 e->ops->release(e); 417 else 418 kfree(e->metaval); 419 } 420 module_put(e->ops->owner); 421 kfree(e); 422 } 423} 424 425static void tcf_ife_cleanup(struct tc_action *a) 426{ 427 struct tcf_ife_info *ife = to_ife(a); 428 struct tcf_ife_params *p; 429 430 spin_lock_bh(&ife->tcf_lock); 431 _tcf_ife_cleanup(a); 432 spin_unlock_bh(&ife->tcf_lock); 433 434 p = rcu_dereference_protected(ife->params, 1); 435 if (p) 436 kfree_rcu(p, rcu); 437} 438 439static int load_metalist(struct nlattr **tb, bool rtnl_held) 440{ 441 int i; 442 443 for (i = 1; i < max_metacnt; i++) { 444 if (tb[i]) { 445 void *val = nla_data(tb[i]); 446 int len = nla_len(tb[i]); 447 int rc; 448 449 rc = load_metaops_and_vet(i, val, len, rtnl_held); 450 if (rc != 0) 451 return rc; 452 } 453 } 454 455 return 0; 456} 457 458static int populate_metalist(struct tcf_ife_info *ife, struct nlattr **tb, 459 bool exists, bool rtnl_held) 460{ 461 int len = 0; 462 int rc = 0; 463 int i = 0; 464 void *val; 465 466 for (i = 1; i < max_metacnt; i++) { 467 if (tb[i]) { 468 val = nla_data(tb[i]); 469 len = nla_len(tb[i]); 470 471 rc = add_metainfo(ife, i, val, len, exists); 472 if (rc) 473 return rc; 474 } 475 } 476 477 return rc; 478} 479 480static int tcf_ife_init(struct net *net, struct nlattr *nla, 481 struct nlattr *est, struct tc_action **a, 482 struct tcf_proto *tp, u32 flags, 483 struct netlink_ext_ack *extack) 484{ 485 struct tc_action_net *tn = net_generic(net, ife_net_id); 486 bool bind = flags & TCA_ACT_FLAGS_BIND; 487 struct nlattr *tb[TCA_IFE_MAX + 1]; 488 struct nlattr *tb2[IFE_META_MAX + 1]; 489 struct tcf_chain *goto_ch = NULL; 490 struct tcf_ife_params *p; 491 struct tcf_ife_info *ife; 492 u16 ife_type = ETH_P_IFE; 493 struct tc_ife *parm; 494 u8 *daddr = NULL; 495 u8 *saddr = NULL; 496 bool exists = false; 497 int ret = 0; 498 u32 index; 499 int err; 500 501 if (!nla) { 502 NL_SET_ERR_MSG_MOD(extack, "IFE requires attributes to be passed"); 503 return -EINVAL; 504 } 505 506 err = nla_parse_nested_deprecated(tb, TCA_IFE_MAX, nla, ife_policy, 507 NULL); 508 if (err < 0) 509 return err; 510 511 if (!tb[TCA_IFE_PARMS]) 512 return -EINVAL; 513 514 parm = nla_data(tb[TCA_IFE_PARMS]); 515 516 /* IFE_DECODE is 0 and indicates the opposite of IFE_ENCODE because 517 * they cannot run as the same time. Check on all other values which 518 * are not supported right now. 519 */ 520 if (parm->flags & ~IFE_ENCODE) 521 return -EINVAL; 522 523 p = kzalloc(sizeof(*p), GFP_KERNEL); 524 if (!p) 525 return -ENOMEM; 526 527 if (tb[TCA_IFE_METALST]) { 528 err = nla_parse_nested_deprecated(tb2, IFE_META_MAX, 529 tb[TCA_IFE_METALST], NULL, 530 NULL); 531 if (err) { 532 kfree(p); 533 return err; 534 } 535 err = load_metalist(tb2, !(flags & TCA_ACT_FLAGS_NO_RTNL)); 536 if (err) { 537 kfree(p); 538 return err; 539 } 540 } 541 542 index = parm->index; 543 err = tcf_idr_check_alloc(tn, &index, a, bind); 544 if (err < 0) { 545 kfree(p); 546 return err; 547 } 548 exists = err; 549 if (exists && bind) { 550 kfree(p); 551 return 0; 552 } 553 554 if (!exists) { 555 ret = tcf_idr_create(tn, index, est, a, &act_ife_ops, 556 bind, true, flags); 557 if (ret) { 558 tcf_idr_cleanup(tn, index); 559 kfree(p); 560 return ret; 561 } 562 ret = ACT_P_CREATED; 563 } else if (!(flags & TCA_ACT_FLAGS_REPLACE)) { 564 tcf_idr_release(*a, bind); 565 kfree(p); 566 return -EEXIST; 567 } 568 569 ife = to_ife(*a); 570 if (ret == ACT_P_CREATED) 571 INIT_LIST_HEAD(&ife->metalist); 572 573 err = tcf_action_check_ctrlact(parm->action, tp, &goto_ch, extack); 574 if (err < 0) 575 goto release_idr; 576 577 p->flags = parm->flags; 578 579 if (parm->flags & IFE_ENCODE) { 580 if (tb[TCA_IFE_TYPE]) 581 ife_type = nla_get_u16(tb[TCA_IFE_TYPE]); 582 if (tb[TCA_IFE_DMAC]) 583 daddr = nla_data(tb[TCA_IFE_DMAC]); 584 if (tb[TCA_IFE_SMAC]) 585 saddr = nla_data(tb[TCA_IFE_SMAC]); 586 } 587 588 if (parm->flags & IFE_ENCODE) { 589 if (daddr) 590 ether_addr_copy(p->eth_dst, daddr); 591 else 592 eth_zero_addr(p->eth_dst); 593 594 if (saddr) 595 ether_addr_copy(p->eth_src, saddr); 596 else 597 eth_zero_addr(p->eth_src); 598 599 p->eth_type = ife_type; 600 } 601 602 if (tb[TCA_IFE_METALST]) { 603 err = populate_metalist(ife, tb2, exists, 604 !(flags & TCA_ACT_FLAGS_NO_RTNL)); 605 if (err) 606 goto metadata_parse_err; 607 } else { 608 /* if no passed metadata allow list or passed allow-all 609 * then here we process by adding as many supported metadatum 610 * as we can. You better have at least one else we are 611 * going to bail out 612 */ 613 err = use_all_metadata(ife, exists); 614 if (err) 615 goto metadata_parse_err; 616 } 617 618 if (exists) 619 spin_lock_bh(&ife->tcf_lock); 620 /* protected by tcf_lock when modifying existing action */ 621 goto_ch = tcf_action_set_ctrlact(*a, parm->action, goto_ch); 622 p = rcu_replace_pointer(ife->params, p, 1); 623 624 if (exists) 625 spin_unlock_bh(&ife->tcf_lock); 626 if (goto_ch) 627 tcf_chain_put_by_act(goto_ch); 628 if (p) 629 kfree_rcu(p, rcu); 630 631 return ret; 632metadata_parse_err: 633 if (goto_ch) 634 tcf_chain_put_by_act(goto_ch); 635release_idr: 636 kfree(p); 637 tcf_idr_release(*a, bind); 638 return err; 639} 640 641static int tcf_ife_dump(struct sk_buff *skb, struct tc_action *a, int bind, 642 int ref) 643{ 644 unsigned char *b = skb_tail_pointer(skb); 645 struct tcf_ife_info *ife = to_ife(a); 646 struct tcf_ife_params *p; 647 struct tc_ife opt = { 648 .index = ife->tcf_index, 649 .refcnt = refcount_read(&ife->tcf_refcnt) - ref, 650 .bindcnt = atomic_read(&ife->tcf_bindcnt) - bind, 651 }; 652 struct tcf_t t; 653 654 spin_lock_bh(&ife->tcf_lock); 655 opt.action = ife->tcf_action; 656 p = rcu_dereference_protected(ife->params, 657 lockdep_is_held(&ife->tcf_lock)); 658 opt.flags = p->flags; 659 660 if (nla_put(skb, TCA_IFE_PARMS, sizeof(opt), &opt)) 661 goto nla_put_failure; 662 663 tcf_tm_dump(&t, &ife->tcf_tm); 664 if (nla_put_64bit(skb, TCA_IFE_TM, sizeof(t), &t, TCA_IFE_PAD)) 665 goto nla_put_failure; 666 667 if (!is_zero_ether_addr(p->eth_dst)) { 668 if (nla_put(skb, TCA_IFE_DMAC, ETH_ALEN, p->eth_dst)) 669 goto nla_put_failure; 670 } 671 672 if (!is_zero_ether_addr(p->eth_src)) { 673 if (nla_put(skb, TCA_IFE_SMAC, ETH_ALEN, p->eth_src)) 674 goto nla_put_failure; 675 } 676 677 if (nla_put(skb, TCA_IFE_TYPE, 2, &p->eth_type)) 678 goto nla_put_failure; 679 680 if (dump_metalist(skb, ife)) { 681 /*ignore failure to dump metalist */ 682 pr_info("Failed to dump metalist\n"); 683 } 684 685 spin_unlock_bh(&ife->tcf_lock); 686 return skb->len; 687 688nla_put_failure: 689 spin_unlock_bh(&ife->tcf_lock); 690 nlmsg_trim(skb, b); 691 return -1; 692} 693 694static int find_decode_metaid(struct sk_buff *skb, struct tcf_ife_info *ife, 695 u16 metaid, u16 mlen, void *mdata) 696{ 697 struct tcf_meta_info *e; 698 699 /* XXX: use hash to speed up */ 700 list_for_each_entry(e, &ife->metalist, metalist) { 701 if (metaid == e->metaid) { 702 if (e->ops) { 703 /* We check for decode presence already */ 704 return e->ops->decode(skb, mdata, mlen); 705 } 706 } 707 } 708 709 return -ENOENT; 710} 711 712static int tcf_ife_decode(struct sk_buff *skb, const struct tc_action *a, 713 struct tcf_result *res) 714{ 715 struct tcf_ife_info *ife = to_ife(a); 716 int action = ife->tcf_action; 717 u8 *ifehdr_end; 718 u8 *tlv_data; 719 u16 metalen; 720 721 bstats_update(this_cpu_ptr(ife->common.cpu_bstats), skb); 722 tcf_lastuse_update(&ife->tcf_tm); 723 724 if (skb_at_tc_ingress(skb)) 725 skb_push(skb, skb->dev->hard_header_len); 726 727 tlv_data = ife_decode(skb, &metalen); 728 if (unlikely(!tlv_data)) { 729 qstats_drop_inc(this_cpu_ptr(ife->common.cpu_qstats)); 730 return TC_ACT_SHOT; 731 } 732 733 ifehdr_end = tlv_data + metalen; 734 for (; tlv_data < ifehdr_end; tlv_data = ife_tlv_meta_next(tlv_data)) { 735 u8 *curr_data; 736 u16 mtype; 737 u16 dlen; 738 739 curr_data = ife_tlv_meta_decode(tlv_data, ifehdr_end, &mtype, 740 &dlen, NULL); 741 if (!curr_data) { 742 qstats_drop_inc(this_cpu_ptr(ife->common.cpu_qstats)); 743 return TC_ACT_SHOT; 744 } 745 746 if (find_decode_metaid(skb, ife, mtype, dlen, curr_data)) { 747 /* abuse overlimits to count when we receive metadata 748 * but dont have an ops for it 749 */ 750 pr_info_ratelimited("Unknown metaid %d dlen %d\n", 751 mtype, dlen); 752 qstats_overlimit_inc(this_cpu_ptr(ife->common.cpu_qstats)); 753 } 754 } 755 756 if (WARN_ON(tlv_data != ifehdr_end)) { 757 qstats_drop_inc(this_cpu_ptr(ife->common.cpu_qstats)); 758 return TC_ACT_SHOT; 759 } 760 761 skb->protocol = eth_type_trans(skb, skb->dev); 762 skb_reset_network_header(skb); 763 764 return action; 765} 766 767/*XXX: check if we can do this at install time instead of current 768 * send data path 769**/ 770static int ife_get_sz(struct sk_buff *skb, struct tcf_ife_info *ife) 771{ 772 struct tcf_meta_info *e, *n; 773 int tot_run_sz = 0, run_sz = 0; 774 775 list_for_each_entry_safe(e, n, &ife->metalist, metalist) { 776 if (e->ops->check_presence) { 777 run_sz = e->ops->check_presence(skb, e); 778 tot_run_sz += run_sz; 779 } 780 } 781 782 return tot_run_sz; 783} 784 785static int tcf_ife_encode(struct sk_buff *skb, const struct tc_action *a, 786 struct tcf_result *res, struct tcf_ife_params *p) 787{ 788 struct tcf_ife_info *ife = to_ife(a); 789 int action = ife->tcf_action; 790 struct ethhdr *oethh; /* outer ether header */ 791 struct tcf_meta_info *e; 792 /* 793 OUTERHDR:TOTMETALEN:{TLVHDR:Metadatum:TLVHDR..}:ORIGDATA 794 where ORIGDATA = original ethernet header ... 795 */ 796 u16 metalen = ife_get_sz(skb, ife); 797 int hdrm = metalen + skb->dev->hard_header_len + IFE_METAHDRLEN; 798 unsigned int skboff = 0; 799 int new_len = skb->len + hdrm; 800 bool exceed_mtu = false; 801 void *ife_meta; 802 int err = 0; 803 804 if (!skb_at_tc_ingress(skb)) { 805 if (new_len > skb->dev->mtu) 806 exceed_mtu = true; 807 } 808 809 bstats_update(this_cpu_ptr(ife->common.cpu_bstats), skb); 810 tcf_lastuse_update(&ife->tcf_tm); 811 812 if (!metalen) { /* no metadata to send */ 813 /* abuse overlimits to count when we allow packet 814 * with no metadata 815 */ 816 qstats_overlimit_inc(this_cpu_ptr(ife->common.cpu_qstats)); 817 return action; 818 } 819 /* could be stupid policy setup or mtu config 820 * so lets be conservative.. */ 821 if ((action == TC_ACT_SHOT) || exceed_mtu) { 822 qstats_drop_inc(this_cpu_ptr(ife->common.cpu_qstats)); 823 return TC_ACT_SHOT; 824 } 825 826 if (skb_at_tc_ingress(skb)) 827 skb_push(skb, skb->dev->hard_header_len); 828 829 ife_meta = ife_encode(skb, metalen); 830 831 spin_lock(&ife->tcf_lock); 832 833 /* XXX: we dont have a clever way of telling encode to 834 * not repeat some of the computations that are done by 835 * ops->presence_check... 836 */ 837 list_for_each_entry(e, &ife->metalist, metalist) { 838 if (e->ops->encode) { 839 err = e->ops->encode(skb, (void *)(ife_meta + skboff), 840 e); 841 } 842 if (err < 0) { 843 /* too corrupt to keep around if overwritten */ 844 spin_unlock(&ife->tcf_lock); 845 qstats_drop_inc(this_cpu_ptr(ife->common.cpu_qstats)); 846 return TC_ACT_SHOT; 847 } 848 skboff += err; 849 } 850 spin_unlock(&ife->tcf_lock); 851 oethh = (struct ethhdr *)skb->data; 852 853 if (!is_zero_ether_addr(p->eth_src)) 854 ether_addr_copy(oethh->h_source, p->eth_src); 855 if (!is_zero_ether_addr(p->eth_dst)) 856 ether_addr_copy(oethh->h_dest, p->eth_dst); 857 oethh->h_proto = htons(p->eth_type); 858 859 if (skb_at_tc_ingress(skb)) 860 skb_pull(skb, skb->dev->hard_header_len); 861 862 return action; 863} 864 865static int tcf_ife_act(struct sk_buff *skb, 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 881static int tcf_ife_walker(struct net *net, struct sk_buff *skb, 882 struct netlink_callback *cb, int type, 883 const struct tc_action_ops *ops, 884 struct netlink_ext_ack *extack) 885{ 886 struct tc_action_net *tn = net_generic(net, ife_net_id); 887 888 return tcf_generic_walker(tn, skb, cb, type, ops, extack); 889} 890 891static int tcf_ife_search(struct net *net, struct tc_action **a, u32 index) 892{ 893 struct tc_action_net *tn = net_generic(net, ife_net_id); 894 895 return tcf_idr_search(tn, a, index); 896} 897 898static struct tc_action_ops act_ife_ops = { 899 .kind = "ife", 900 .id = TCA_ID_IFE, 901 .owner = THIS_MODULE, 902 .act = tcf_ife_act, 903 .dump = tcf_ife_dump, 904 .cleanup = tcf_ife_cleanup, 905 .init = tcf_ife_init, 906 .walk = tcf_ife_walker, 907 .lookup = tcf_ife_search, 908 .size = sizeof(struct tcf_ife_info), 909}; 910 911static __net_init int ife_init_net(struct net *net) 912{ 913 struct tc_action_net *tn = net_generic(net, ife_net_id); 914 915 return tc_action_net_init(net, tn, &act_ife_ops); 916} 917 918static void __net_exit ife_exit_net(struct list_head *net_list) 919{ 920 tc_action_net_exit(net_list, ife_net_id); 921} 922 923static struct pernet_operations ife_net_ops = { 924 .init = ife_init_net, 925 .exit_batch = ife_exit_net, 926 .id = &ife_net_id, 927 .size = sizeof(struct tc_action_net), 928}; 929 930static int __init ife_init_module(void) 931{ 932 return tcf_register_action(&act_ife_ops, &ife_net_ops); 933} 934 935static void __exit ife_cleanup_module(void) 936{ 937 tcf_unregister_action(&act_ife_ops, &ife_net_ops); 938} 939 940module_init(ife_init_module); 941module_exit(ife_cleanup_module); 942 943MODULE_AUTHOR("Jamal Hadi Salim(2015)"); 944MODULE_DESCRIPTION("Inter-FE LFB action"); 945MODULE_LICENSE("GPL");