aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVinicius Costa Gomes <vinicius.gomes@intel.com>2018-04-10 13:49:59 -0400
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>2018-04-25 14:07:51 -0400
commite086be9ab21cc2a0894e0f72ff8c974aba0b296e (patch)
tree6d7e8e8b23e29f8cab210e46fe41cad02e3c83af
parentf8f3d34e5470c48a10c27c4f6f65e149e10d04ec (diff)
igb: Add support for adding offloaded clsflower filters
This allows filters added by tc-flower and specifying MAC addresses, Ethernet types, and the VLAN priority field, to be offloaded to the controller. This reuses most of the infrastructure used by ethtool, but clsflower filters are kept in a separated list, so they are invisible to ethtool. To setup clsflower offloading: $ tc qdisc replace dev eth0 handle 100: parent root mqprio \ num_tc 3 map 2 2 1 0 2 2 2 2 2 2 2 2 2 2 2 2 \ queues 1@0 1@1 2@2 hw 0 (clsflower offloading depends on the netword driver to be configured with multiple traffic classes, we use mqprio's 'num_tc' parameter to set it to 3) $ tc qdisc add dev eth0 ingress Examples of filters: $ tc filter add dev eth0 parent ffff: flower \ dst_mac aa:aa:aa:aa:aa:aa \ hw_tc 2 skip_sw (just a simple filter filtering for the destination MAC address and steering that traffic to queue 2) $ tc filter add dev enp2s0 parent ffff: proto 0x22f0 flower \ src_mac cc:cc:cc:cc:cc:cc \ hw_tc 1 skip_sw (as the i210 doesn't support steering traffic based on the source address alone, we need to use another steering traffic, in this case we are using the ethernet type (0x22f0) to steer traffic to queue 1) Signed-off-by: Vinicius Costa Gomes <vinicius.gomes@intel.com> Tested-by: Aaron Brown <aaron.f.brown@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
-rw-r--r--drivers/net/ethernet/intel/igb/igb.h2
-rw-r--r--drivers/net/ethernet/intel/igb/igb_main.c188
2 files changed, 188 insertions, 2 deletions
diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h
index 0eac1df499f8..990a7fb32e4e 100644
--- a/drivers/net/ethernet/intel/igb/igb.h
+++ b/drivers/net/ethernet/intel/igb/igb.h
@@ -465,6 +465,7 @@ struct igb_nfc_input {
465struct igb_nfc_filter { 465struct igb_nfc_filter {
466 struct hlist_node nfc_node; 466 struct hlist_node nfc_node;
467 struct igb_nfc_input filter; 467 struct igb_nfc_input filter;
468 unsigned long cookie;
468 u16 etype_reg_index; 469 u16 etype_reg_index;
469 u16 sw_idx; 470 u16 sw_idx;
470 u16 action; 471 u16 action;
@@ -604,6 +605,7 @@ struct igb_adapter {
604 605
605 /* RX network flow classification support */ 606 /* RX network flow classification support */
606 struct hlist_head nfc_filter_list; 607 struct hlist_head nfc_filter_list;
608 struct hlist_head cls_flower_list;
607 unsigned int nfc_filter_count; 609 unsigned int nfc_filter_count;
608 /* lock for RX network flow classification filter */ 610 /* lock for RX network flow classification filter */
609 spinlock_t nfc_lock; 611 spinlock_t nfc_lock;
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index 26b0f0efc97e..3ce43207a35f 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -2514,16 +2514,197 @@ static int igb_offload_cbs(struct igb_adapter *adapter,
2514 return 0; 2514 return 0;
2515} 2515}
2516 2516
2517#define ETHER_TYPE_FULL_MASK ((__force __be16)~0)
2518#define VLAN_PRIO_FULL_MASK (0x07)
2519
2520static int igb_parse_cls_flower(struct igb_adapter *adapter,
2521 struct tc_cls_flower_offload *f,
2522 int traffic_class,
2523 struct igb_nfc_filter *input)
2524{
2525 struct netlink_ext_ack *extack = f->common.extack;
2526
2527 if (f->dissector->used_keys &
2528 ~(BIT(FLOW_DISSECTOR_KEY_BASIC) |
2529 BIT(FLOW_DISSECTOR_KEY_CONTROL) |
2530 BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
2531 BIT(FLOW_DISSECTOR_KEY_VLAN))) {
2532 NL_SET_ERR_MSG_MOD(extack,
2533 "Unsupported key used, only BASIC, CONTROL, ETH_ADDRS and VLAN are supported");
2534 return -EOPNOTSUPP;
2535 }
2536
2537 if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
2538 struct flow_dissector_key_eth_addrs *key, *mask;
2539
2540 key = skb_flow_dissector_target(f->dissector,
2541 FLOW_DISSECTOR_KEY_ETH_ADDRS,
2542 f->key);
2543 mask = skb_flow_dissector_target(f->dissector,
2544 FLOW_DISSECTOR_KEY_ETH_ADDRS,
2545 f->mask);
2546
2547 if (!is_zero_ether_addr(mask->dst)) {
2548 if (!is_broadcast_ether_addr(mask->dst)) {
2549 NL_SET_ERR_MSG_MOD(extack, "Only full masks are supported for destination MAC address");
2550 return -EINVAL;
2551 }
2552
2553 input->filter.match_flags |=
2554 IGB_FILTER_FLAG_DST_MAC_ADDR;
2555 ether_addr_copy(input->filter.dst_addr, key->dst);
2556 }
2557
2558 if (!is_zero_ether_addr(mask->src)) {
2559 if (!is_broadcast_ether_addr(mask->src)) {
2560 NL_SET_ERR_MSG_MOD(extack, "Only full masks are supported for source MAC address");
2561 return -EINVAL;
2562 }
2563
2564 input->filter.match_flags |=
2565 IGB_FILTER_FLAG_SRC_MAC_ADDR;
2566 ether_addr_copy(input->filter.src_addr, key->src);
2567 }
2568 }
2569
2570 if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_BASIC)) {
2571 struct flow_dissector_key_basic *key, *mask;
2572
2573 key = skb_flow_dissector_target(f->dissector,
2574 FLOW_DISSECTOR_KEY_BASIC,
2575 f->key);
2576 mask = skb_flow_dissector_target(f->dissector,
2577 FLOW_DISSECTOR_KEY_BASIC,
2578 f->mask);
2579
2580 if (mask->n_proto) {
2581 if (mask->n_proto != ETHER_TYPE_FULL_MASK) {
2582 NL_SET_ERR_MSG_MOD(extack, "Only full mask is supported for EtherType filter");
2583 return -EINVAL;
2584 }
2585
2586 input->filter.match_flags |= IGB_FILTER_FLAG_ETHER_TYPE;
2587 input->filter.etype = key->n_proto;
2588 }
2589 }
2590
2591 if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_VLAN)) {
2592 struct flow_dissector_key_vlan *key, *mask;
2593
2594 key = skb_flow_dissector_target(f->dissector,
2595 FLOW_DISSECTOR_KEY_VLAN,
2596 f->key);
2597 mask = skb_flow_dissector_target(f->dissector,
2598 FLOW_DISSECTOR_KEY_VLAN,
2599 f->mask);
2600
2601 if (mask->vlan_priority) {
2602 if (mask->vlan_priority != VLAN_PRIO_FULL_MASK) {
2603 NL_SET_ERR_MSG_MOD(extack, "Only full mask is supported for VLAN priority");
2604 return -EINVAL;
2605 }
2606
2607 input->filter.match_flags |= IGB_FILTER_FLAG_VLAN_TCI;
2608 input->filter.vlan_tci = key->vlan_priority;
2609 }
2610 }
2611
2612 input->action = traffic_class;
2613 input->cookie = f->cookie;
2614
2615 return 0;
2616}
2617
2517static int igb_configure_clsflower(struct igb_adapter *adapter, 2618static int igb_configure_clsflower(struct igb_adapter *adapter,
2518 struct tc_cls_flower_offload *cls_flower) 2619 struct tc_cls_flower_offload *cls_flower)
2519{ 2620{
2520 return -EOPNOTSUPP; 2621 struct netlink_ext_ack *extack = cls_flower->common.extack;
2622 struct igb_nfc_filter *filter, *f;
2623 int err, tc;
2624
2625 tc = tc_classid_to_hwtc(adapter->netdev, cls_flower->classid);
2626 if (tc < 0) {
2627 NL_SET_ERR_MSG_MOD(extack, "Invalid traffic class");
2628 return -EINVAL;
2629 }
2630
2631 filter = kzalloc(sizeof(*filter), GFP_KERNEL);
2632 if (!filter)
2633 return -ENOMEM;
2634
2635 err = igb_parse_cls_flower(adapter, cls_flower, tc, filter);
2636 if (err < 0)
2637 goto err_parse;
2638
2639 spin_lock(&adapter->nfc_lock);
2640
2641 hlist_for_each_entry(f, &adapter->nfc_filter_list, nfc_node) {
2642 if (!memcmp(&f->filter, &filter->filter, sizeof(f->filter))) {
2643 err = -EEXIST;
2644 NL_SET_ERR_MSG_MOD(extack,
2645 "This filter is already set in ethtool");
2646 goto err_locked;
2647 }
2648 }
2649
2650 hlist_for_each_entry(f, &adapter->cls_flower_list, nfc_node) {
2651 if (!memcmp(&f->filter, &filter->filter, sizeof(f->filter))) {
2652 err = -EEXIST;
2653 NL_SET_ERR_MSG_MOD(extack,
2654 "This filter is already set in cls_flower");
2655 goto err_locked;
2656 }
2657 }
2658
2659 err = igb_add_filter(adapter, filter);
2660 if (err < 0) {
2661 NL_SET_ERR_MSG_MOD(extack, "Could not add filter to the adapter");
2662 goto err_locked;
2663 }
2664
2665 hlist_add_head(&filter->nfc_node, &adapter->cls_flower_list);
2666
2667 spin_unlock(&adapter->nfc_lock);
2668
2669 return 0;
2670
2671err_locked:
2672 spin_unlock(&adapter->nfc_lock);
2673
2674err_parse:
2675 kfree(filter);
2676
2677 return err;
2521} 2678}
2522 2679
2523static int igb_delete_clsflower(struct igb_adapter *adapter, 2680static int igb_delete_clsflower(struct igb_adapter *adapter,
2524 struct tc_cls_flower_offload *cls_flower) 2681 struct tc_cls_flower_offload *cls_flower)
2525{ 2682{
2526 return -EOPNOTSUPP; 2683 struct igb_nfc_filter *filter;
2684 int err;
2685
2686 spin_lock(&adapter->nfc_lock);
2687
2688 hlist_for_each_entry(filter, &adapter->cls_flower_list, nfc_node)
2689 if (filter->cookie == cls_flower->cookie)
2690 break;
2691
2692 if (!filter) {
2693 err = -ENOENT;
2694 goto out;
2695 }
2696
2697 err = igb_erase_filter(adapter, filter);
2698 if (err < 0)
2699 goto out;
2700
2701 hlist_del(&filter->nfc_node);
2702 kfree(filter);
2703
2704out:
2705 spin_unlock(&adapter->nfc_lock);
2706
2707 return err;
2527} 2708}
2528 2709
2529static int igb_setup_tc_cls_flower(struct igb_adapter *adapter, 2710static int igb_setup_tc_cls_flower(struct igb_adapter *adapter,
@@ -9368,6 +9549,9 @@ static void igb_nfc_filter_exit(struct igb_adapter *adapter)
9368 hlist_for_each_entry(rule, &adapter->nfc_filter_list, nfc_node) 9549 hlist_for_each_entry(rule, &adapter->nfc_filter_list, nfc_node)
9369 igb_erase_filter(adapter, rule); 9550 igb_erase_filter(adapter, rule);
9370 9551
9552 hlist_for_each_entry(rule, &adapter->cls_flower_list, nfc_node)
9553 igb_erase_filter(adapter, rule);
9554
9371 spin_unlock(&adapter->nfc_lock); 9555 spin_unlock(&adapter->nfc_lock);
9372} 9556}
9373 9557