Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'mlxsw-Add-support-for-egress-and-policy-based-sampling'

Ido Schimmel says:

====================
mlxsw: Add support for egress and policy-based sampling

So far mlxsw only supported ingress sampling using matchall classifier.
This series adds support for egress sampling and policy-based sampling
using flower classifier on Spectrum-2 and newer ASICs. As such, it is
now possible to issue these commands:

# tc filter add dev swp1 egress pref 1 proto all matchall action sample rate 100 group 1

# tc filter add dev swp2 ingress pref 1 proto ip flower dst_ip 198.51.100.1 action sample rate 100 group 2

When performing egress sampling (using either matchall or flower) the
ASIC is able to report the end-to-end latency which is passed to the
psample module.

Series overview:

Patches #1-#3 are preparations without any functional changes

Patch #4 generalizes the idea of sampling triggers and creates a hash
table to track active sampling triggers in preparation for egress and
policy-based triggers. The motivation is explained in the changelog

Patch #5 flips mlxsw to start using this hash table instead of storing
ingress sampling triggers as an attribute of the sampled port

Patch #6 finally adds support for egress sampling using matchall
classifier

Patches #7-#8 add support for policy-based sampling using flower
classifier

Patches #9 extends the mlxsw sampling selftest to cover the new triggers

Patch #10 makes sure that egress sampling configuration only fails on
Spectrum-1
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+808 -79
+131
drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.c
··· 2007 2007 return 0; 2008 2008 } 2009 2009 EXPORT_SYMBOL(mlxsw_afa_block_append_l4port); 2010 + 2011 + /* Mirror Sampler Action 2012 + * --------------------- 2013 + * The SAMPLER_ACTION is used to mirror packets with a probability (sampling). 2014 + */ 2015 + 2016 + #define MLXSW_AFA_SAMPLER_CODE 0x13 2017 + #define MLXSW_AFA_SAMPLER_SIZE 1 2018 + 2019 + /* afa_sampler_mirror_agent 2020 + * Mirror (SPAN) agent. 2021 + */ 2022 + MLXSW_ITEM32(afa, sampler, mirror_agent, 0x04, 0, 3); 2023 + 2024 + #define MLXSW_AFA_SAMPLER_RATE_MAX (BIT(24) - 1) 2025 + 2026 + /* afa_sampler_mirror_probability_rate 2027 + * Mirroring probability. 2028 + * Valid values are 1 to 2^24 - 1 2029 + */ 2030 + MLXSW_ITEM32(afa, sampler, mirror_probability_rate, 0x08, 0, 24); 2031 + 2032 + static void mlxsw_afa_sampler_pack(char *payload, u8 mirror_agent, u32 rate) 2033 + { 2034 + mlxsw_afa_sampler_mirror_agent_set(payload, mirror_agent); 2035 + mlxsw_afa_sampler_mirror_probability_rate_set(payload, rate); 2036 + } 2037 + 2038 + struct mlxsw_afa_sampler { 2039 + struct mlxsw_afa_resource resource; 2040 + int span_id; 2041 + u8 local_port; 2042 + bool ingress; 2043 + }; 2044 + 2045 + static void mlxsw_afa_sampler_destroy(struct mlxsw_afa_block *block, 2046 + struct mlxsw_afa_sampler *sampler) 2047 + { 2048 + mlxsw_afa_resource_del(&sampler->resource); 2049 + block->afa->ops->sampler_del(block->afa->ops_priv, sampler->local_port, 2050 + sampler->span_id, sampler->ingress); 2051 + kfree(sampler); 2052 + } 2053 + 2054 + static void mlxsw_afa_sampler_destructor(struct mlxsw_afa_block *block, 2055 + struct mlxsw_afa_resource *resource) 2056 + { 2057 + struct mlxsw_afa_sampler *sampler; 2058 + 2059 + sampler = container_of(resource, struct mlxsw_afa_sampler, resource); 2060 + mlxsw_afa_sampler_destroy(block, sampler); 2061 + } 2062 + 2063 + static struct mlxsw_afa_sampler * 2064 + mlxsw_afa_sampler_create(struct mlxsw_afa_block *block, u8 local_port, 2065 + struct psample_group *psample_group, u32 rate, 2066 + u32 trunc_size, bool truncate, bool ingress, 2067 + struct netlink_ext_ack *extack) 2068 + { 2069 + struct mlxsw_afa_sampler *sampler; 2070 + int err; 2071 + 2072 + sampler = kzalloc(sizeof(*sampler), GFP_KERNEL); 2073 + if (!sampler) 2074 + return ERR_PTR(-ENOMEM); 2075 + 2076 + err = block->afa->ops->sampler_add(block->afa->ops_priv, local_port, 2077 + psample_group, rate, trunc_size, 2078 + truncate, ingress, &sampler->span_id, 2079 + extack); 2080 + if (err) 2081 + goto err_sampler_add; 2082 + 2083 + sampler->ingress = ingress; 2084 + sampler->local_port = local_port; 2085 + sampler->resource.destructor = mlxsw_afa_sampler_destructor; 2086 + mlxsw_afa_resource_add(block, &sampler->resource); 2087 + return sampler; 2088 + 2089 + err_sampler_add: 2090 + kfree(sampler); 2091 + return ERR_PTR(err); 2092 + } 2093 + 2094 + static int 2095 + mlxsw_afa_block_append_allocated_sampler(struct mlxsw_afa_block *block, 2096 + u8 mirror_agent, u32 rate) 2097 + { 2098 + char *act = mlxsw_afa_block_append_action(block, MLXSW_AFA_SAMPLER_CODE, 2099 + MLXSW_AFA_SAMPLER_SIZE); 2100 + 2101 + if (IS_ERR(act)) 2102 + return PTR_ERR(act); 2103 + mlxsw_afa_sampler_pack(act, mirror_agent, rate); 2104 + return 0; 2105 + } 2106 + 2107 + int mlxsw_afa_block_append_sampler(struct mlxsw_afa_block *block, u8 local_port, 2108 + struct psample_group *psample_group, 2109 + u32 rate, u32 trunc_size, bool truncate, 2110 + bool ingress, 2111 + struct netlink_ext_ack *extack) 2112 + { 2113 + struct mlxsw_afa_sampler *sampler; 2114 + int err; 2115 + 2116 + if (rate > MLXSW_AFA_SAMPLER_RATE_MAX) { 2117 + NL_SET_ERR_MSG_MOD(extack, "Sampling rate is too high"); 2118 + return -EINVAL; 2119 + } 2120 + 2121 + sampler = mlxsw_afa_sampler_create(block, local_port, psample_group, 2122 + rate, trunc_size, truncate, ingress, 2123 + extack); 2124 + if (IS_ERR(sampler)) 2125 + return PTR_ERR(sampler); 2126 + 2127 + err = mlxsw_afa_block_append_allocated_sampler(block, sampler->span_id, 2128 + rate); 2129 + if (err) { 2130 + NL_SET_ERR_MSG_MOD(extack, "Cannot append sampler action"); 2131 + goto err_append_allocated_sampler; 2132 + } 2133 + 2134 + return 0; 2135 + 2136 + err_append_allocated_sampler: 2137 + mlxsw_afa_sampler_destroy(block, sampler); 2138 + return err; 2139 + } 2140 + EXPORT_SYMBOL(mlxsw_afa_block_append_sampler);
+11
drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.h
··· 30 30 u16 *p_policer_index, 31 31 struct netlink_ext_ack *extack); 32 32 void (*policer_del)(void *priv, u16 policer_index); 33 + int (*sampler_add)(void *priv, u8 local_port, 34 + struct psample_group *psample_group, u32 rate, 35 + u32 trunc_size, bool truncate, bool ingress, 36 + int *p_span_id, struct netlink_ext_ack *extack); 37 + void (*sampler_del)(void *priv, u8 local_port, int span_id, 38 + bool ingress); 33 39 bool dummy_first_set; 34 40 }; 35 41 ··· 98 92 u32 fa_index, u64 rate_bytes_ps, u32 burst, 99 93 u16 *p_policer_index, 100 94 struct netlink_ext_ack *extack); 95 + int mlxsw_afa_block_append_sampler(struct mlxsw_afa_block *block, u8 local_port, 96 + struct psample_group *psample_group, 97 + u32 rate, u32 trunc_size, bool truncate, 98 + bool ingress, 99 + struct netlink_ext_ack *extack); 101 100 102 101 #endif
+148
drivers/net/ethernet/mellanox/mlxsw/spectrum.c
··· 23 23 #include <linux/netlink.h> 24 24 #include <linux/jhash.h> 25 25 #include <linux/log2.h> 26 + #include <linux/refcount.h> 27 + #include <linux/rhashtable.h> 26 28 #include <net/switchdev.h> 27 29 #include <net/pkt_cls.h> 28 30 #include <net/netevent.h> ··· 2552 2550 .get_stats = mlxsw_sp2_get_stats, 2553 2551 }; 2554 2552 2553 + struct mlxsw_sp_sample_trigger_node { 2554 + struct mlxsw_sp_sample_trigger trigger; 2555 + struct mlxsw_sp_sample_params params; 2556 + struct rhash_head ht_node; 2557 + struct rcu_head rcu; 2558 + refcount_t refcount; 2559 + }; 2560 + 2561 + static const struct rhashtable_params mlxsw_sp_sample_trigger_ht_params = { 2562 + .key_offset = offsetof(struct mlxsw_sp_sample_trigger_node, trigger), 2563 + .head_offset = offsetof(struct mlxsw_sp_sample_trigger_node, ht_node), 2564 + .key_len = sizeof(struct mlxsw_sp_sample_trigger), 2565 + .automatic_shrinking = true, 2566 + }; 2567 + 2568 + static void 2569 + mlxsw_sp_sample_trigger_key_init(struct mlxsw_sp_sample_trigger *key, 2570 + const struct mlxsw_sp_sample_trigger *trigger) 2571 + { 2572 + memset(key, 0, sizeof(*key)); 2573 + key->type = trigger->type; 2574 + key->local_port = trigger->local_port; 2575 + } 2576 + 2577 + /* RCU read lock must be held */ 2578 + struct mlxsw_sp_sample_params * 2579 + mlxsw_sp_sample_trigger_params_lookup(struct mlxsw_sp *mlxsw_sp, 2580 + const struct mlxsw_sp_sample_trigger *trigger) 2581 + { 2582 + struct mlxsw_sp_sample_trigger_node *trigger_node; 2583 + struct mlxsw_sp_sample_trigger key; 2584 + 2585 + mlxsw_sp_sample_trigger_key_init(&key, trigger); 2586 + trigger_node = rhashtable_lookup(&mlxsw_sp->sample_trigger_ht, &key, 2587 + mlxsw_sp_sample_trigger_ht_params); 2588 + if (!trigger_node) 2589 + return NULL; 2590 + 2591 + return &trigger_node->params; 2592 + } 2593 + 2594 + static int 2595 + mlxsw_sp_sample_trigger_node_init(struct mlxsw_sp *mlxsw_sp, 2596 + const struct mlxsw_sp_sample_trigger *trigger, 2597 + const struct mlxsw_sp_sample_params *params) 2598 + { 2599 + struct mlxsw_sp_sample_trigger_node *trigger_node; 2600 + int err; 2601 + 2602 + trigger_node = kzalloc(sizeof(*trigger_node), GFP_KERNEL); 2603 + if (!trigger_node) 2604 + return -ENOMEM; 2605 + 2606 + trigger_node->trigger = *trigger; 2607 + trigger_node->params = *params; 2608 + refcount_set(&trigger_node->refcount, 1); 2609 + 2610 + err = rhashtable_insert_fast(&mlxsw_sp->sample_trigger_ht, 2611 + &trigger_node->ht_node, 2612 + mlxsw_sp_sample_trigger_ht_params); 2613 + if (err) 2614 + goto err_rhashtable_insert; 2615 + 2616 + return 0; 2617 + 2618 + err_rhashtable_insert: 2619 + kfree(trigger_node); 2620 + return err; 2621 + } 2622 + 2623 + static void 2624 + mlxsw_sp_sample_trigger_node_fini(struct mlxsw_sp *mlxsw_sp, 2625 + struct mlxsw_sp_sample_trigger_node *trigger_node) 2626 + { 2627 + rhashtable_remove_fast(&mlxsw_sp->sample_trigger_ht, 2628 + &trigger_node->ht_node, 2629 + mlxsw_sp_sample_trigger_ht_params); 2630 + kfree_rcu(trigger_node, rcu); 2631 + } 2632 + 2633 + int 2634 + mlxsw_sp_sample_trigger_params_set(struct mlxsw_sp *mlxsw_sp, 2635 + const struct mlxsw_sp_sample_trigger *trigger, 2636 + const struct mlxsw_sp_sample_params *params, 2637 + struct netlink_ext_ack *extack) 2638 + { 2639 + struct mlxsw_sp_sample_trigger_node *trigger_node; 2640 + struct mlxsw_sp_sample_trigger key; 2641 + 2642 + ASSERT_RTNL(); 2643 + 2644 + mlxsw_sp_sample_trigger_key_init(&key, trigger); 2645 + 2646 + trigger_node = rhashtable_lookup_fast(&mlxsw_sp->sample_trigger_ht, 2647 + &key, 2648 + mlxsw_sp_sample_trigger_ht_params); 2649 + if (!trigger_node) 2650 + return mlxsw_sp_sample_trigger_node_init(mlxsw_sp, &key, 2651 + params); 2652 + 2653 + if (trigger_node->params.psample_group != params->psample_group || 2654 + trigger_node->params.truncate != params->truncate || 2655 + trigger_node->params.rate != params->rate || 2656 + trigger_node->params.trunc_size != params->trunc_size) { 2657 + NL_SET_ERR_MSG_MOD(extack, "Sampling parameters do not match for an existing sampling trigger"); 2658 + return -EINVAL; 2659 + } 2660 + 2661 + refcount_inc(&trigger_node->refcount); 2662 + 2663 + return 0; 2664 + } 2665 + 2666 + void 2667 + mlxsw_sp_sample_trigger_params_unset(struct mlxsw_sp *mlxsw_sp, 2668 + const struct mlxsw_sp_sample_trigger *trigger) 2669 + { 2670 + struct mlxsw_sp_sample_trigger_node *trigger_node; 2671 + struct mlxsw_sp_sample_trigger key; 2672 + 2673 + ASSERT_RTNL(); 2674 + 2675 + mlxsw_sp_sample_trigger_key_init(&key, trigger); 2676 + 2677 + trigger_node = rhashtable_lookup_fast(&mlxsw_sp->sample_trigger_ht, 2678 + &key, 2679 + mlxsw_sp_sample_trigger_ht_params); 2680 + if (!trigger_node) 2681 + return; 2682 + 2683 + if (!refcount_dec_and_test(&trigger_node->refcount)) 2684 + return; 2685 + 2686 + mlxsw_sp_sample_trigger_node_fini(mlxsw_sp, trigger_node); 2687 + } 2688 + 2555 2689 static int mlxsw_sp_netdevice_event(struct notifier_block *unused, 2556 2690 unsigned long event, void *ptr); 2557 2691 ··· 2842 2704 goto err_port_module_info_init; 2843 2705 } 2844 2706 2707 + err = rhashtable_init(&mlxsw_sp->sample_trigger_ht, 2708 + &mlxsw_sp_sample_trigger_ht_params); 2709 + if (err) { 2710 + dev_err(mlxsw_sp->bus_info->dev, "Failed to init sampling trigger hashtable\n"); 2711 + goto err_sample_trigger_init; 2712 + } 2713 + 2845 2714 err = mlxsw_sp_ports_create(mlxsw_sp); 2846 2715 if (err) { 2847 2716 dev_err(mlxsw_sp->bus_info->dev, "Failed to create ports\n"); ··· 2858 2713 return 0; 2859 2714 2860 2715 err_ports_create: 2716 + rhashtable_destroy(&mlxsw_sp->sample_trigger_ht); 2717 + err_sample_trigger_init: 2861 2718 mlxsw_sp_port_module_info_fini(mlxsw_sp); 2862 2719 err_port_module_info_init: 2863 2720 mlxsw_sp_dpipe_fini(mlxsw_sp); ··· 2994 2847 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 2995 2848 2996 2849 mlxsw_sp_ports_remove(mlxsw_sp); 2850 + rhashtable_destroy(&mlxsw_sp->sample_trigger_ht); 2997 2851 mlxsw_sp_port_module_info_fini(mlxsw_sp); 2998 2852 mlxsw_sp_dpipe_fini(mlxsw_sp); 2999 2853 unregister_netdevice_notifier_net(mlxsw_sp_net(mlxsw_sp),
+45 -7
drivers/net/ethernet/mellanox/mlxsw/spectrum.h
··· 16 16 #include <linux/in6.h> 17 17 #include <linux/notifier.h> 18 18 #include <linux/net_namespace.h> 19 + #include <linux/spinlock.h> 19 20 #include <net/psample.h> 20 21 #include <net/pkt_cls.h> 21 22 #include <net/red.h> ··· 134 133 struct mlxsw_sp_ptp_ops; 135 134 struct mlxsw_sp_span_ops; 136 135 struct mlxsw_sp_qdisc_state; 136 + struct mlxsw_sp_mall_entry; 137 137 138 138 struct mlxsw_sp_port_mapping { 139 139 u8 module; ··· 150 148 const unsigned char *mac_mask; 151 149 struct mlxsw_sp_upper *lags; 152 150 struct mlxsw_sp_port_mapping **port_mapping; 151 + struct rhashtable sample_trigger_ht; 153 152 struct mlxsw_sp_sb *sb; 154 153 struct mlxsw_sp_bridge *bridge; 155 154 struct mlxsw_sp_router *router; ··· 236 233 u32 tx_dropped; 237 234 }; 238 235 239 - struct mlxsw_sp_port_sample { 236 + enum mlxsw_sp_sample_trigger_type { 237 + MLXSW_SP_SAMPLE_TRIGGER_TYPE_INGRESS, 238 + MLXSW_SP_SAMPLE_TRIGGER_TYPE_EGRESS, 239 + MLXSW_SP_SAMPLE_TRIGGER_TYPE_POLICY_ENGINE, 240 + }; 241 + 242 + struct mlxsw_sp_sample_trigger { 243 + enum mlxsw_sp_sample_trigger_type type; 244 + u8 local_port; /* Reserved when trigger type is not ingress / egress. */ 245 + }; 246 + 247 + struct mlxsw_sp_sample_params { 240 248 struct psample_group *psample_group; 241 249 u32 trunc_size; 242 250 u32 rate; 243 251 bool truncate; 244 - int span_id; /* Relevant for Spectrum-2 onwards. */ 245 252 }; 246 253 247 254 struct mlxsw_sp_bridge_port; ··· 317 304 struct mlxsw_sp_port_xstats xstats; 318 305 struct delayed_work update_dw; 319 306 } periodic_hw_stats; 320 - struct mlxsw_sp_port_sample __rcu *sample; 321 307 struct list_head vlans_list; 322 308 struct mlxsw_sp_port_vlan *default_vlan; 323 309 struct mlxsw_sp_qdisc_state *qdisc; ··· 545 533 struct mlxsw_sp_hdroom *hdroom); 546 534 int mlxsw_sp_hdroom_configure(struct mlxsw_sp_port *mlxsw_sp_port, 547 535 const struct mlxsw_sp_hdroom *hdroom); 536 + struct mlxsw_sp_sample_params * 537 + mlxsw_sp_sample_trigger_params_lookup(struct mlxsw_sp *mlxsw_sp, 538 + const struct mlxsw_sp_sample_trigger *trigger); 539 + int 540 + mlxsw_sp_sample_trigger_params_set(struct mlxsw_sp *mlxsw_sp, 541 + const struct mlxsw_sp_sample_trigger *trigger, 542 + const struct mlxsw_sp_sample_params *params, 543 + struct netlink_ext_ack *extack); 544 + void 545 + mlxsw_sp_sample_trigger_params_unset(struct mlxsw_sp *mlxsw_sp, 546 + const struct mlxsw_sp_sample_trigger *trigger); 548 547 549 548 extern const struct mlxsw_sp_sb_vals mlxsw_sp1_sb_vals; 550 549 extern const struct mlxsw_sp_sb_vals mlxsw_sp2_sb_vals; ··· 947 924 int mlxsw_sp_acl_rulei_act_fid_set(struct mlxsw_sp *mlxsw_sp, 948 925 struct mlxsw_sp_acl_rule_info *rulei, 949 926 u16 fid, struct netlink_ext_ack *extack); 927 + int mlxsw_sp_acl_rulei_act_sample(struct mlxsw_sp *mlxsw_sp, 928 + struct mlxsw_sp_acl_rule_info *rulei, 929 + struct mlxsw_sp_flow_block *block, 930 + struct psample_group *psample_group, u32 rate, 931 + u32 trunc_size, bool truncate, 932 + struct netlink_ext_ack *extack); 950 933 951 934 struct mlxsw_sp_acl_rule; 952 935 ··· 1064 1035 /* spectrum_matchall.c */ 1065 1036 struct mlxsw_sp_mall_ops { 1066 1037 int (*sample_add)(struct mlxsw_sp *mlxsw_sp, 1067 - struct mlxsw_sp_port *mlxsw_sp_port, u32 rate); 1038 + struct mlxsw_sp_port *mlxsw_sp_port, 1039 + struct mlxsw_sp_mall_entry *mall_entry, 1040 + struct netlink_ext_ack *extack); 1068 1041 void (*sample_del)(struct mlxsw_sp *mlxsw_sp, 1069 - struct mlxsw_sp_port *mlxsw_sp_port); 1042 + struct mlxsw_sp_port *mlxsw_sp_port, 1043 + struct mlxsw_sp_mall_entry *mall_entry); 1070 1044 }; 1071 1045 1072 1046 extern const struct mlxsw_sp_mall_ops mlxsw_sp1_mall_ops; ··· 1090 1058 int span_id; 1091 1059 }; 1092 1060 1061 + struct mlxsw_sp_mall_sample_entry { 1062 + struct mlxsw_sp_sample_params params; 1063 + int span_id; /* Relevant for Spectrum-2 onwards. */ 1064 + }; 1065 + 1093 1066 struct mlxsw_sp_mall_entry { 1094 1067 struct list_head list; 1095 1068 unsigned long cookie; ··· 1104 1067 union { 1105 1068 struct mlxsw_sp_mall_mirror_entry mirror; 1106 1069 struct mlxsw_sp_mall_trap_entry trap; 1107 - struct mlxsw_sp_port_sample sample; 1070 + struct mlxsw_sp_mall_sample_entry sample; 1108 1071 }; 1109 1072 struct rcu_head rcu; 1110 1073 }; ··· 1115 1078 void mlxsw_sp_mall_destroy(struct mlxsw_sp_flow_block *block, 1116 1079 struct tc_cls_matchall_offload *f); 1117 1080 int mlxsw_sp_mall_port_bind(struct mlxsw_sp_flow_block *block, 1118 - struct mlxsw_sp_port *mlxsw_sp_port); 1081 + struct mlxsw_sp_port *mlxsw_sp_port, 1082 + struct netlink_ext_ack *extack); 1119 1083 void mlxsw_sp_mall_port_unbind(struct mlxsw_sp_flow_block *block, 1120 1084 struct mlxsw_sp_port *mlxsw_sp_port); 1121 1085 int mlxsw_sp_mall_prio_get(struct mlxsw_sp_flow_block *block, u32 chain_index,
+25
drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c
··· 688 688 return mlxsw_afa_block_append_fid_set(rulei->act_block, fid, extack); 689 689 } 690 690 691 + int mlxsw_sp_acl_rulei_act_sample(struct mlxsw_sp *mlxsw_sp, 692 + struct mlxsw_sp_acl_rule_info *rulei, 693 + struct mlxsw_sp_flow_block *block, 694 + struct psample_group *psample_group, u32 rate, 695 + u32 trunc_size, bool truncate, 696 + struct netlink_ext_ack *extack) 697 + { 698 + struct mlxsw_sp_flow_block_binding *binding; 699 + struct mlxsw_sp_port *mlxsw_sp_port; 700 + 701 + if (!list_is_singular(&block->binding_list)) { 702 + NL_SET_ERR_MSG_MOD(extack, "Only a single sampling source is allowed"); 703 + return -EOPNOTSUPP; 704 + } 705 + binding = list_first_entry(&block->binding_list, 706 + struct mlxsw_sp_flow_block_binding, list); 707 + mlxsw_sp_port = binding->mlxsw_sp_port; 708 + 709 + return mlxsw_afa_block_append_sampler(rulei->act_block, 710 + mlxsw_sp_port->local_port, 711 + psample_group, rate, trunc_size, 712 + truncate, binding->ingress, 713 + extack); 714 + } 715 + 691 716 struct mlxsw_sp_acl_rule * 692 717 mlxsw_sp_acl_rule_create(struct mlxsw_sp *mlxsw_sp, 693 718 struct mlxsw_sp_acl_ruleset *ruleset,
+83
drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_actions.c
··· 192 192 policer_index); 193 193 } 194 194 195 + static int mlxsw_sp1_act_sampler_add(void *priv, u8 local_port, 196 + struct psample_group *psample_group, 197 + u32 rate, u32 trunc_size, bool truncate, 198 + bool ingress, int *p_span_id, 199 + struct netlink_ext_ack *extack) 200 + { 201 + NL_SET_ERR_MSG_MOD(extack, "Sampling action is not supported on Spectrum-1"); 202 + return -EOPNOTSUPP; 203 + } 204 + 205 + static void mlxsw_sp1_act_sampler_del(void *priv, u8 local_port, int span_id, 206 + bool ingress) 207 + { 208 + WARN_ON_ONCE(1); 209 + } 210 + 195 211 const struct mlxsw_afa_ops mlxsw_sp1_act_afa_ops = { 196 212 .kvdl_set_add = mlxsw_sp1_act_kvdl_set_add, 197 213 .kvdl_set_del = mlxsw_sp_act_kvdl_set_del, ··· 220 204 .mirror_del = mlxsw_sp_act_mirror_del, 221 205 .policer_add = mlxsw_sp_act_policer_add, 222 206 .policer_del = mlxsw_sp_act_policer_del, 207 + .sampler_add = mlxsw_sp1_act_sampler_add, 208 + .sampler_del = mlxsw_sp1_act_sampler_del, 223 209 }; 210 + 211 + static int mlxsw_sp2_act_sampler_add(void *priv, u8 local_port, 212 + struct psample_group *psample_group, 213 + u32 rate, u32 trunc_size, bool truncate, 214 + bool ingress, int *p_span_id, 215 + struct netlink_ext_ack *extack) 216 + { 217 + struct mlxsw_sp_span_agent_parms agent_parms = { 218 + .session_id = MLXSW_SP_SPAN_SESSION_ID_SAMPLING, 219 + }; 220 + struct mlxsw_sp_sample_trigger trigger = { 221 + .type = MLXSW_SP_SAMPLE_TRIGGER_TYPE_POLICY_ENGINE, 222 + }; 223 + struct mlxsw_sp_sample_params params; 224 + struct mlxsw_sp_port *mlxsw_sp_port; 225 + struct mlxsw_sp *mlxsw_sp = priv; 226 + int err; 227 + 228 + params.psample_group = psample_group; 229 + params.trunc_size = trunc_size; 230 + params.rate = rate; 231 + params.truncate = truncate; 232 + err = mlxsw_sp_sample_trigger_params_set(mlxsw_sp, &trigger, &params, 233 + extack); 234 + if (err) 235 + return err; 236 + 237 + err = mlxsw_sp_span_agent_get(mlxsw_sp, p_span_id, &agent_parms); 238 + if (err) { 239 + NL_SET_ERR_MSG_MOD(extack, "Failed to get SPAN agent"); 240 + goto err_span_agent_get; 241 + } 242 + 243 + mlxsw_sp_port = mlxsw_sp->ports[local_port]; 244 + err = mlxsw_sp_span_analyzed_port_get(mlxsw_sp_port, ingress); 245 + if (err) { 246 + NL_SET_ERR_MSG_MOD(extack, "Failed to get analyzed port"); 247 + goto err_analyzed_port_get; 248 + } 249 + 250 + return 0; 251 + 252 + err_analyzed_port_get: 253 + mlxsw_sp_span_agent_put(mlxsw_sp, *p_span_id); 254 + err_span_agent_get: 255 + mlxsw_sp_sample_trigger_params_unset(mlxsw_sp, &trigger); 256 + return err; 257 + } 258 + 259 + static void mlxsw_sp2_act_sampler_del(void *priv, u8 local_port, int span_id, 260 + bool ingress) 261 + { 262 + struct mlxsw_sp_sample_trigger trigger = { 263 + .type = MLXSW_SP_SAMPLE_TRIGGER_TYPE_POLICY_ENGINE, 264 + }; 265 + struct mlxsw_sp_port *mlxsw_sp_port; 266 + struct mlxsw_sp *mlxsw_sp = priv; 267 + 268 + mlxsw_sp_port = mlxsw_sp->ports[local_port]; 269 + mlxsw_sp_span_analyzed_port_put(mlxsw_sp_port, ingress); 270 + mlxsw_sp_span_agent_put(mlxsw_sp, span_id); 271 + mlxsw_sp_sample_trigger_params_unset(mlxsw_sp, &trigger); 272 + } 224 273 225 274 const struct mlxsw_afa_ops mlxsw_sp2_act_afa_ops = { 226 275 .kvdl_set_add = mlxsw_sp2_act_kvdl_set_add, ··· 299 218 .mirror_del = mlxsw_sp_act_mirror_del, 300 219 .policer_add = mlxsw_sp_act_policer_add, 301 220 .policer_del = mlxsw_sp_act_policer_del, 221 + .sampler_add = mlxsw_sp2_act_sampler_add, 222 + .sampler_del = mlxsw_sp2_act_sampler_del, 302 223 .dummy_first_set = true, 303 224 }; 304 225
+1 -1
drivers/net/ethernet/mellanox/mlxsw/spectrum_flow.c
··· 71 71 return -EOPNOTSUPP; 72 72 } 73 73 74 - err = mlxsw_sp_mall_port_bind(block, mlxsw_sp_port); 74 + err = mlxsw_sp_mall_port_bind(block, mlxsw_sp_port, extack); 75 75 if (err) 76 76 return err; 77 77
+18
drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c
··· 24 24 const struct flow_action_entry *act; 25 25 int mirror_act_count = 0; 26 26 int police_act_count = 0; 27 + int sample_act_count = 0; 27 28 int err, i; 28 29 29 30 if (!flow_action_has_entries(flow_action)) ··· 206 205 act->police.index, 207 206 act->police.rate_bytes_ps, 208 207 burst, extack); 208 + if (err) 209 + return err; 210 + break; 211 + } 212 + case FLOW_ACTION_SAMPLE: { 213 + if (sample_act_count++) { 214 + NL_SET_ERR_MSG_MOD(extack, "Multiple sample actions per rule are not supported"); 215 + return -EOPNOTSUPP; 216 + } 217 + 218 + err = mlxsw_sp_acl_rulei_act_sample(mlxsw_sp, rulei, 219 + block, 220 + act->sample.psample_group, 221 + act->sample.rate, 222 + act->sample.trunc_size, 223 + act->sample.truncate, 224 + extack); 209 225 if (err) 210 226 return err; 211 227 break;
+103 -64
drivers/net/ethernet/mellanox/mlxsw/spectrum_matchall.c
··· 24 24 25 25 static int 26 26 mlxsw_sp_mall_port_mirror_add(struct mlxsw_sp_port *mlxsw_sp_port, 27 - struct mlxsw_sp_mall_entry *mall_entry) 27 + struct mlxsw_sp_mall_entry *mall_entry, 28 + struct netlink_ext_ack *extack) 28 29 { 29 30 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 30 31 struct mlxsw_sp_span_agent_parms agent_parms = {}; ··· 34 33 int err; 35 34 36 35 if (!mall_entry->mirror.to_dev) { 37 - netdev_err(mlxsw_sp_port->dev, "Could not find requested device\n"); 36 + NL_SET_ERR_MSG(extack, "Could not find requested device"); 38 37 return -EINVAL; 39 38 } 40 39 41 40 agent_parms.to_dev = mall_entry->mirror.to_dev; 42 41 err = mlxsw_sp_span_agent_get(mlxsw_sp, &mall_entry->mirror.span_id, 43 42 &agent_parms); 44 - if (err) 43 + if (err) { 44 + NL_SET_ERR_MSG(extack, "Failed to get SPAN agent"); 45 45 return err; 46 + } 46 47 47 48 err = mlxsw_sp_span_analyzed_port_get(mlxsw_sp_port, 48 49 mall_entry->ingress); 49 - if (err) 50 + if (err) { 51 + NL_SET_ERR_MSG(extack, "Failed to get analyzed port"); 50 52 goto err_analyzed_port_get; 53 + } 51 54 52 55 trigger = mall_entry->ingress ? MLXSW_SP_SPAN_TRIGGER_INGRESS : 53 56 MLXSW_SP_SPAN_TRIGGER_EGRESS; ··· 59 54 parms.probability_rate = 1; 60 55 err = mlxsw_sp_span_agent_bind(mlxsw_sp, trigger, mlxsw_sp_port, 61 56 &parms); 62 - if (err) 57 + if (err) { 58 + NL_SET_ERR_MSG(extack, "Failed to bind SPAN agent"); 63 59 goto err_agent_bind; 60 + } 64 61 65 62 return 0; 66 63 ··· 101 94 102 95 static int 103 96 mlxsw_sp_mall_port_sample_add(struct mlxsw_sp_port *mlxsw_sp_port, 104 - struct mlxsw_sp_mall_entry *mall_entry) 97 + struct mlxsw_sp_mall_entry *mall_entry, 98 + struct netlink_ext_ack *extack) 105 99 { 106 100 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 101 + struct mlxsw_sp_sample_trigger trigger; 107 102 int err; 108 103 109 - if (rtnl_dereference(mlxsw_sp_port->sample)) { 110 - netdev_err(mlxsw_sp_port->dev, "sample already active\n"); 111 - return -EEXIST; 112 - } 113 - rcu_assign_pointer(mlxsw_sp_port->sample, &mall_entry->sample); 104 + if (mall_entry->ingress) 105 + trigger.type = MLXSW_SP_SAMPLE_TRIGGER_TYPE_INGRESS; 106 + else 107 + trigger.type = MLXSW_SP_SAMPLE_TRIGGER_TYPE_EGRESS; 108 + trigger.local_port = mlxsw_sp_port->local_port; 109 + err = mlxsw_sp_sample_trigger_params_set(mlxsw_sp, &trigger, 110 + &mall_entry->sample.params, 111 + extack); 112 + if (err) 113 + return err; 114 114 115 115 err = mlxsw_sp->mall_ops->sample_add(mlxsw_sp, mlxsw_sp_port, 116 - mall_entry->sample.rate); 116 + mall_entry, extack); 117 117 if (err) 118 118 goto err_port_sample_set; 119 119 return 0; 120 120 121 121 err_port_sample_set: 122 - RCU_INIT_POINTER(mlxsw_sp_port->sample, NULL); 122 + mlxsw_sp_sample_trigger_params_unset(mlxsw_sp, &trigger); 123 123 return err; 124 124 } 125 125 126 126 static void 127 - mlxsw_sp_mall_port_sample_del(struct mlxsw_sp_port *mlxsw_sp_port) 127 + mlxsw_sp_mall_port_sample_del(struct mlxsw_sp_port *mlxsw_sp_port, 128 + struct mlxsw_sp_mall_entry *mall_entry) 128 129 { 129 130 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 131 + struct mlxsw_sp_sample_trigger trigger; 130 132 131 - if (!mlxsw_sp_port->sample) 132 - return; 133 + if (mall_entry->ingress) 134 + trigger.type = MLXSW_SP_SAMPLE_TRIGGER_TYPE_INGRESS; 135 + else 136 + trigger.type = MLXSW_SP_SAMPLE_TRIGGER_TYPE_EGRESS; 137 + trigger.local_port = mlxsw_sp_port->local_port; 133 138 134 - mlxsw_sp->mall_ops->sample_del(mlxsw_sp, mlxsw_sp_port); 135 - RCU_INIT_POINTER(mlxsw_sp_port->sample, NULL); 139 + mlxsw_sp->mall_ops->sample_del(mlxsw_sp, mlxsw_sp_port, mall_entry); 140 + mlxsw_sp_sample_trigger_params_unset(mlxsw_sp, &trigger); 136 141 } 137 142 138 143 static int 139 144 mlxsw_sp_mall_port_rule_add(struct mlxsw_sp_port *mlxsw_sp_port, 140 - struct mlxsw_sp_mall_entry *mall_entry) 145 + struct mlxsw_sp_mall_entry *mall_entry, 146 + struct netlink_ext_ack *extack) 141 147 { 142 148 switch (mall_entry->type) { 143 149 case MLXSW_SP_MALL_ACTION_TYPE_MIRROR: 144 - return mlxsw_sp_mall_port_mirror_add(mlxsw_sp_port, mall_entry); 150 + return mlxsw_sp_mall_port_mirror_add(mlxsw_sp_port, mall_entry, 151 + extack); 145 152 case MLXSW_SP_MALL_ACTION_TYPE_SAMPLE: 146 - return mlxsw_sp_mall_port_sample_add(mlxsw_sp_port, mall_entry); 153 + return mlxsw_sp_mall_port_sample_add(mlxsw_sp_port, mall_entry, 154 + extack); 147 155 default: 148 156 WARN_ON(1); 149 157 return -EINVAL; ··· 174 152 mlxsw_sp_mall_port_mirror_del(mlxsw_sp_port, mall_entry); 175 153 break; 176 154 case MLXSW_SP_MALL_ACTION_TYPE_SAMPLE: 177 - mlxsw_sp_mall_port_sample_del(mlxsw_sp_port); 155 + mlxsw_sp_mall_port_sample_del(mlxsw_sp_port, mall_entry); 178 156 break; 179 157 default: 180 158 WARN_ON(1); ··· 264 242 mall_entry->mirror.to_dev = act->dev; 265 243 } else if (act->id == FLOW_ACTION_SAMPLE && 266 244 protocol == htons(ETH_P_ALL)) { 267 - if (!mall_entry->ingress) { 268 - NL_SET_ERR_MSG(f->common.extack, "Sample is not supported on egress"); 269 - err = -EOPNOTSUPP; 270 - goto errout; 271 - } 272 245 if (flower_prio_valid && 273 246 mall_entry->priority >= flower_min_prio) { 274 247 NL_SET_ERR_MSG(f->common.extack, "Failed to add behind existing flower rules"); 275 248 err = -EOPNOTSUPP; 276 249 goto errout; 277 250 } 278 - if (act->sample.rate > MLXSW_REG_MPSC_RATE_MAX) { 279 - NL_SET_ERR_MSG(f->common.extack, "Sample rate not supported"); 280 - err = -EOPNOTSUPP; 281 - goto errout; 282 - } 283 251 mall_entry->type = MLXSW_SP_MALL_ACTION_TYPE_SAMPLE; 284 - mall_entry->sample.psample_group = act->sample.psample_group; 285 - mall_entry->sample.truncate = act->sample.truncate; 286 - mall_entry->sample.trunc_size = act->sample.trunc_size; 287 - mall_entry->sample.rate = act->sample.rate; 252 + mall_entry->sample.params.psample_group = act->sample.psample_group; 253 + mall_entry->sample.params.truncate = act->sample.truncate; 254 + mall_entry->sample.params.trunc_size = act->sample.trunc_size; 255 + mall_entry->sample.params.rate = act->sample.rate; 288 256 } else { 289 257 err = -EOPNOTSUPP; 290 258 goto errout; ··· 282 270 283 271 list_for_each_entry(binding, &block->binding_list, list) { 284 272 err = mlxsw_sp_mall_port_rule_add(binding->mlxsw_sp_port, 285 - mall_entry); 273 + mall_entry, f->common.extack); 286 274 if (err) 287 275 goto rollback; 288 276 } ··· 330 318 } 331 319 332 320 int mlxsw_sp_mall_port_bind(struct mlxsw_sp_flow_block *block, 333 - struct mlxsw_sp_port *mlxsw_sp_port) 321 + struct mlxsw_sp_port *mlxsw_sp_port, 322 + struct netlink_ext_ack *extack) 334 323 { 335 324 struct mlxsw_sp_mall_entry *mall_entry; 336 325 int err; 337 326 338 327 list_for_each_entry(mall_entry, &block->mall.list, list) { 339 - err = mlxsw_sp_mall_port_rule_add(mlxsw_sp_port, mall_entry); 328 + err = mlxsw_sp_mall_port_rule_add(mlxsw_sp_port, mall_entry, 329 + extack); 340 330 if (err) 341 331 goto rollback; 342 332 } ··· 376 362 377 363 static int mlxsw_sp1_mall_sample_add(struct mlxsw_sp *mlxsw_sp, 378 364 struct mlxsw_sp_port *mlxsw_sp_port, 379 - u32 rate) 365 + struct mlxsw_sp_mall_entry *mall_entry, 366 + struct netlink_ext_ack *extack) 380 367 { 368 + u32 rate = mall_entry->sample.params.rate; 369 + 370 + if (!mall_entry->ingress) { 371 + NL_SET_ERR_MSG(extack, "Sampling is not supported on egress"); 372 + return -EOPNOTSUPP; 373 + } 374 + 375 + if (rate > MLXSW_REG_MPSC_RATE_MAX) { 376 + NL_SET_ERR_MSG(extack, "Unsupported sampling rate"); 377 + return -EOPNOTSUPP; 378 + } 379 + 381 380 return mlxsw_sp_mall_port_sample_set(mlxsw_sp_port, true, rate); 382 381 } 383 382 384 383 static void mlxsw_sp1_mall_sample_del(struct mlxsw_sp *mlxsw_sp, 385 - struct mlxsw_sp_port *mlxsw_sp_port) 384 + struct mlxsw_sp_port *mlxsw_sp_port, 385 + struct mlxsw_sp_mall_entry *mall_entry) 386 386 { 387 387 mlxsw_sp_mall_port_sample_set(mlxsw_sp_port, false, 1); 388 388 } ··· 408 380 409 381 static int mlxsw_sp2_mall_sample_add(struct mlxsw_sp *mlxsw_sp, 410 382 struct mlxsw_sp_port *mlxsw_sp_port, 411 - u32 rate) 383 + struct mlxsw_sp_mall_entry *mall_entry, 384 + struct netlink_ext_ack *extack) 412 385 { 413 386 struct mlxsw_sp_span_trigger_parms trigger_parms = {}; 414 387 struct mlxsw_sp_span_agent_parms agent_parms = { 415 388 .to_dev = NULL, /* Mirror to CPU. */ 416 389 .session_id = MLXSW_SP_SPAN_SESSION_ID_SAMPLING, 417 390 }; 418 - struct mlxsw_sp_port_sample *sample; 391 + u32 rate = mall_entry->sample.params.rate; 392 + enum mlxsw_sp_span_trigger span_trigger; 419 393 int err; 420 394 421 - sample = rtnl_dereference(mlxsw_sp_port->sample); 422 - 423 - err = mlxsw_sp_span_agent_get(mlxsw_sp, &sample->span_id, &agent_parms); 424 - if (err) 395 + err = mlxsw_sp_span_agent_get(mlxsw_sp, &mall_entry->sample.span_id, 396 + &agent_parms); 397 + if (err) { 398 + NL_SET_ERR_MSG(extack, "Failed to get SPAN agent"); 425 399 return err; 400 + } 426 401 427 - err = mlxsw_sp_span_analyzed_port_get(mlxsw_sp_port, true); 428 - if (err) 402 + err = mlxsw_sp_span_analyzed_port_get(mlxsw_sp_port, 403 + mall_entry->ingress); 404 + if (err) { 405 + NL_SET_ERR_MSG(extack, "Failed to get analyzed port"); 429 406 goto err_analyzed_port_get; 407 + } 430 408 431 - trigger_parms.span_id = sample->span_id; 409 + span_trigger = mall_entry->ingress ? MLXSW_SP_SPAN_TRIGGER_INGRESS : 410 + MLXSW_SP_SPAN_TRIGGER_EGRESS; 411 + trigger_parms.span_id = mall_entry->sample.span_id; 432 412 trigger_parms.probability_rate = rate; 433 - err = mlxsw_sp_span_agent_bind(mlxsw_sp, MLXSW_SP_SPAN_TRIGGER_INGRESS, 434 - mlxsw_sp_port, &trigger_parms); 435 - if (err) 413 + err = mlxsw_sp_span_agent_bind(mlxsw_sp, span_trigger, mlxsw_sp_port, 414 + &trigger_parms); 415 + if (err) { 416 + NL_SET_ERR_MSG(extack, "Failed to bind SPAN agent"); 436 417 goto err_agent_bind; 418 + } 437 419 438 420 return 0; 439 421 440 422 err_agent_bind: 441 - mlxsw_sp_span_analyzed_port_put(mlxsw_sp_port, true); 423 + mlxsw_sp_span_analyzed_port_put(mlxsw_sp_port, mall_entry->ingress); 442 424 err_analyzed_port_get: 443 - mlxsw_sp_span_agent_put(mlxsw_sp, sample->span_id); 425 + mlxsw_sp_span_agent_put(mlxsw_sp, mall_entry->sample.span_id); 444 426 return err; 445 427 } 446 428 447 429 static void mlxsw_sp2_mall_sample_del(struct mlxsw_sp *mlxsw_sp, 448 - struct mlxsw_sp_port *mlxsw_sp_port) 430 + struct mlxsw_sp_port *mlxsw_sp_port, 431 + struct mlxsw_sp_mall_entry *mall_entry) 449 432 { 450 433 struct mlxsw_sp_span_trigger_parms trigger_parms = {}; 451 - struct mlxsw_sp_port_sample *sample; 434 + enum mlxsw_sp_span_trigger span_trigger; 452 435 453 - sample = rtnl_dereference(mlxsw_sp_port->sample); 454 - 455 - trigger_parms.span_id = sample->span_id; 456 - mlxsw_sp_span_agent_unbind(mlxsw_sp, MLXSW_SP_SPAN_TRIGGER_INGRESS, 457 - mlxsw_sp_port, &trigger_parms); 458 - mlxsw_sp_span_analyzed_port_put(mlxsw_sp_port, true); 459 - mlxsw_sp_span_agent_put(mlxsw_sp, sample->span_id); 436 + span_trigger = mall_entry->ingress ? MLXSW_SP_SPAN_TRIGGER_INGRESS : 437 + MLXSW_SP_SPAN_TRIGGER_EGRESS; 438 + trigger_parms.span_id = mall_entry->sample.span_id; 439 + mlxsw_sp_span_agent_unbind(mlxsw_sp, span_trigger, mlxsw_sp_port, 440 + &trigger_parms); 441 + mlxsw_sp_span_analyzed_port_put(mlxsw_sp_port, mall_entry->ingress); 442 + mlxsw_sp_span_agent_put(mlxsw_sp, mall_entry->sample.span_id); 460 443 } 461 444 462 445 const struct mlxsw_sp_mall_ops mlxsw_sp2_mall_ops = {
+105 -6
drivers/net/ethernet/mellanox/mlxsw/spectrum_trap.c
··· 51 51 enum { 52 52 /* Packet was mirrored from ingress. */ 53 53 MLXSW_SP_MIRROR_REASON_INGRESS = 1, 54 + /* Packet was mirrored from policy engine. */ 55 + MLXSW_SP_MIRROR_REASON_POLICY_ENGINE = 2, 54 56 /* Packet was early dropped. */ 55 57 MLXSW_SP_MIRROR_REASON_INGRESS_WRED = 9, 58 + /* Packet was mirrored from egress. */ 59 + MLXSW_SP_MIRROR_REASON_EGRESS = 14, 56 60 }; 57 61 58 62 static int mlxsw_sp_rx_listener(struct mlxsw_sp *mlxsw_sp, struct sk_buff *skb, ··· 261 257 void *trap_ctx) 262 258 { 263 259 struct mlxsw_sp *mlxsw_sp = devlink_trap_ctx_priv(trap_ctx); 260 + struct mlxsw_sp_sample_trigger trigger; 261 + struct mlxsw_sp_sample_params *params; 264 262 struct mlxsw_sp_port *mlxsw_sp_port; 265 - struct mlxsw_sp_port_sample *sample; 266 263 struct psample_metadata md = {}; 267 264 int err; 268 265 ··· 275 270 if (!mlxsw_sp_port) 276 271 goto out; 277 272 278 - sample = rcu_dereference(mlxsw_sp_port->sample); 279 - if (!sample) 273 + trigger.type = MLXSW_SP_SAMPLE_TRIGGER_TYPE_INGRESS; 274 + trigger.local_port = local_port; 275 + params = mlxsw_sp_sample_trigger_params_lookup(mlxsw_sp, &trigger); 276 + if (!params) 280 277 goto out; 281 278 282 279 /* The psample module expects skb->data to point to the start of the ··· 286 279 */ 287 280 skb_push(skb, ETH_HLEN); 288 281 mlxsw_sp_psample_md_init(mlxsw_sp, &md, skb, 289 - mlxsw_sp_port->dev->ifindex, sample->truncate, 290 - sample->trunc_size); 291 - psample_sample_packet(sample->psample_group, skb, sample->rate, &md); 282 + mlxsw_sp_port->dev->ifindex, params->truncate, 283 + params->trunc_size); 284 + psample_sample_packet(params->psample_group, skb, params->rate, &md); 285 + out: 286 + consume_skb(skb); 287 + } 288 + 289 + static void mlxsw_sp_rx_sample_tx_listener(struct sk_buff *skb, u8 local_port, 290 + void *trap_ctx) 291 + { 292 + struct mlxsw_rx_md_info *rx_md_info = &mlxsw_skb_cb(skb)->rx_md_info; 293 + struct mlxsw_sp *mlxsw_sp = devlink_trap_ctx_priv(trap_ctx); 294 + struct mlxsw_sp_port *mlxsw_sp_port, *mlxsw_sp_port_tx; 295 + struct mlxsw_sp_sample_trigger trigger; 296 + struct mlxsw_sp_sample_params *params; 297 + struct psample_metadata md = {}; 298 + int err; 299 + 300 + /* Locally generated packets are not reported from the policy engine 301 + * trigger, so do not report them from the egress trigger as well. 302 + */ 303 + if (local_port == MLXSW_PORT_CPU_PORT) 304 + goto out; 305 + 306 + err = __mlxsw_sp_rx_no_mark_listener(skb, local_port, trap_ctx); 307 + if (err) 308 + return; 309 + 310 + mlxsw_sp_port = mlxsw_sp->ports[local_port]; 311 + if (!mlxsw_sp_port) 312 + goto out; 313 + 314 + /* Packet was sampled from Tx, so we need to retrieve the sample 315 + * parameters based on the Tx port and not the Rx port. 316 + */ 317 + mlxsw_sp_port_tx = mlxsw_sp_sample_tx_port_get(mlxsw_sp, rx_md_info); 318 + if (!mlxsw_sp_port_tx) 319 + goto out; 320 + 321 + trigger.type = MLXSW_SP_SAMPLE_TRIGGER_TYPE_EGRESS; 322 + trigger.local_port = mlxsw_sp_port_tx->local_port; 323 + params = mlxsw_sp_sample_trigger_params_lookup(mlxsw_sp, &trigger); 324 + if (!params) 325 + goto out; 326 + 327 + /* The psample module expects skb->data to point to the start of the 328 + * Ethernet header. 329 + */ 330 + skb_push(skb, ETH_HLEN); 331 + mlxsw_sp_psample_md_init(mlxsw_sp, &md, skb, 332 + mlxsw_sp_port->dev->ifindex, params->truncate, 333 + params->trunc_size); 334 + psample_sample_packet(params->psample_group, skb, params->rate, &md); 335 + out: 336 + consume_skb(skb); 337 + } 338 + 339 + static void mlxsw_sp_rx_sample_acl_listener(struct sk_buff *skb, u8 local_port, 340 + void *trap_ctx) 341 + { 342 + struct mlxsw_sp *mlxsw_sp = devlink_trap_ctx_priv(trap_ctx); 343 + struct mlxsw_sp_sample_trigger trigger = { 344 + .type = MLXSW_SP_SAMPLE_TRIGGER_TYPE_POLICY_ENGINE, 345 + }; 346 + struct mlxsw_sp_sample_params *params; 347 + struct mlxsw_sp_port *mlxsw_sp_port; 348 + struct psample_metadata md = {}; 349 + int err; 350 + 351 + err = __mlxsw_sp_rx_no_mark_listener(skb, local_port, trap_ctx); 352 + if (err) 353 + return; 354 + 355 + mlxsw_sp_port = mlxsw_sp->ports[local_port]; 356 + if (!mlxsw_sp_port) 357 + goto out; 358 + 359 + params = mlxsw_sp_sample_trigger_params_lookup(mlxsw_sp, &trigger); 360 + if (!params) 361 + goto out; 362 + 363 + /* The psample module expects skb->data to point to the start of the 364 + * Ethernet header. 365 + */ 366 + skb_push(skb, ETH_HLEN); 367 + mlxsw_sp_psample_md_init(mlxsw_sp, &md, skb, 368 + mlxsw_sp_port->dev->ifindex, params->truncate, 369 + params->trunc_size); 370 + psample_sample_packet(params->psample_group, skb, params->rate, &md); 292 371 out: 293 372 consume_skb(skb); 294 373 } ··· 1933 1840 MLXSW_RXL_MIRROR(mlxsw_sp_rx_sample_listener, 1, 1934 1841 SP_PKT_SAMPLE, 1935 1842 MLXSW_SP_MIRROR_REASON_INGRESS), 1843 + MLXSW_RXL_MIRROR(mlxsw_sp_rx_sample_tx_listener, 1, 1844 + SP_PKT_SAMPLE, 1845 + MLXSW_SP_MIRROR_REASON_EGRESS), 1846 + MLXSW_RXL_MIRROR(mlxsw_sp_rx_sample_acl_listener, 1, 1847 + SP_PKT_SAMPLE, 1848 + MLXSW_SP_MIRROR_REASON_POLICY_ENGINE), 1936 1849 }, 1937 1850 }, 1938 1851 };
+3 -1
tools/testing/selftests/drivers/net/mlxsw/tc_restrictions.sh
··· 18 18 19 19 source $lib_dir/tc_common.sh 20 20 source $lib_dir/lib.sh 21 + source $lib_dir/devlink_lib.sh 21 22 22 23 switch_create() 23 24 { ··· 167 166 RET=0 168 167 169 168 # It is forbidden in mlxsw driver to have matchall with sample action 170 - # bound on egress 169 + # bound on egress. Spectrum-1 specific restriction 170 + [[ "$DEVLINK_VIDDID" != "15b3:cb84" ]] && return 171 171 172 172 tc qdisc add dev $swp1 clsact 173 173
+135
tools/testing/selftests/drivers/net/mlxsw/tc_sample.sh
··· 41 41 tc_sample_md_lag_oif_test 42 42 tc_sample_md_out_tc_test 43 43 tc_sample_md_out_tc_occ_test 44 + tc_sample_md_latency_test 45 + tc_sample_acl_group_conflict_test 46 + tc_sample_acl_rate_test 47 + tc_sample_acl_max_rate_test 44 48 " 45 49 NUM_NETIFS=8 46 50 CAPTURE_FILE=$(mktemp) ··· 484 480 485 481 tc qdisc del dev $rp2 root handle 1: 486 482 tc filter del dev $rp1 ingress protocol all pref 1 handle 101 matchall 483 + } 484 + 485 + tc_sample_md_latency_test() 486 + { 487 + RET=0 488 + 489 + # Egress sampling not supported on Spectrum-1. 490 + [[ "$DEVLINK_VIDDID" == "15b3:cb84" ]] && return 491 + 492 + tc filter add dev $rp2 egress protocol all pref 1 handle 101 matchall \ 493 + skip_sw action sample rate 5 group 1 494 + check_err $? "Failed to configure sampling rule" 495 + 496 + psample_capture_start 497 + 498 + ip vrf exec v$h1 $MZ $h1 -c 3200 -d 1msec -p 64 -A 192.0.2.1 \ 499 + -B 198.51.100.1 -t udp dp=52768,sp=42768 -q 500 + 501 + psample_capture_stop 502 + 503 + grep -q -e "latency " $CAPTURE_FILE 504 + check_err $? "Sampled packets do not have latency attribute" 505 + 506 + log_test "tc sample latency" 507 + 508 + tc filter del dev $rp2 egress protocol all pref 1 handle 101 matchall 509 + } 510 + 511 + tc_sample_acl_group_conflict_test() 512 + { 513 + RET=0 514 + 515 + # Test that two flower sampling rules cannot be configured on the same 516 + # port with different groups. 517 + 518 + # Policy-based sampling is not supported on Spectrum-1. 519 + [[ "$DEVLINK_VIDDID" == "15b3:cb84" ]] && return 520 + 521 + tc filter add dev $rp1 ingress protocol ip pref 1 handle 101 flower \ 522 + skip_sw action sample rate 1024 group 1 523 + check_err $? "Failed to configure sampling rule" 524 + 525 + tc filter add dev $rp1 ingress protocol ip pref 2 handle 102 flower \ 526 + skip_sw action sample rate 1024 group 1 527 + check_err $? "Failed to configure sampling rule with same group" 528 + 529 + tc filter add dev $rp1 ingress protocol ip pref 3 handle 103 flower \ 530 + skip_sw action sample rate 1024 group 2 &> /dev/null 531 + check_fail $? "Managed to configure sampling rule with conflicting group" 532 + 533 + log_test "tc sample (w/ flower) group conflict test" 534 + 535 + tc filter del dev $rp1 ingress protocol ip pref 2 handle 102 flower 536 + tc filter del dev $rp1 ingress protocol ip pref 1 handle 101 flower 537 + } 538 + 539 + __tc_sample_acl_rate_test() 540 + { 541 + local bind=$1; shift 542 + local port=$1; shift 543 + local pkts pct 544 + 545 + RET=0 546 + 547 + # Policy-based sampling is not supported on Spectrum-1. 548 + [[ "$DEVLINK_VIDDID" == "15b3:cb84" ]] && return 549 + 550 + tc filter add dev $port $bind protocol ip pref 1 handle 101 flower \ 551 + skip_sw dst_ip 198.51.100.1 action sample rate 32 group 1 552 + check_err $? "Failed to configure sampling rule" 553 + 554 + psample_capture_start 555 + 556 + ip vrf exec v$h1 $MZ $h1 -c 3200 -d 1msec -p 64 -A 192.0.2.1 \ 557 + -B 198.51.100.1 -t udp dp=52768,sp=42768 -q 558 + 559 + psample_capture_stop 560 + 561 + pkts=$(grep -e "group 1 " $CAPTURE_FILE | wc -l) 562 + pct=$((100 * (pkts - 100) / 100)) 563 + (( -25 <= pct && pct <= 25)) 564 + check_err $? "Expected 100 packets, got $pkts packets, which is $pct% off. Required accuracy is +-25%" 565 + 566 + # Setup a filter that should not match any packet and make sure packets 567 + # are not sampled. 568 + tc filter del dev $port $bind protocol ip pref 1 handle 101 flower 569 + 570 + tc filter add dev $port $bind protocol ip pref 1 handle 101 flower \ 571 + skip_sw dst_ip 198.51.100.10 action sample rate 32 group 1 572 + check_err $? "Failed to configure sampling rule" 573 + 574 + psample_capture_start 575 + 576 + ip vrf exec v$h1 $MZ $h1 -c 3200 -d 1msec -p 64 -A 192.0.2.1 \ 577 + -B 198.51.100.1 -t udp dp=52768,sp=42768 -q 578 + 579 + psample_capture_stop 580 + 581 + grep -q -e "group 1 " $CAPTURE_FILE 582 + check_fail $? "Sampled packets when should not" 583 + 584 + log_test "tc sample (w/ flower) rate ($bind)" 585 + 586 + tc filter del dev $port $bind protocol ip pref 1 handle 101 flower 587 + } 588 + 589 + tc_sample_acl_rate_test() 590 + { 591 + __tc_sample_acl_rate_test ingress $rp1 592 + __tc_sample_acl_rate_test egress $rp2 593 + } 594 + 595 + tc_sample_acl_max_rate_test() 596 + { 597 + RET=0 598 + 599 + # Policy-based sampling is not supported on Spectrum-1. 600 + [[ "$DEVLINK_VIDDID" == "15b3:cb84" ]] && return 601 + 602 + tc filter add dev $rp1 ingress protocol ip pref 1 handle 101 flower \ 603 + skip_sw action sample rate $((2 ** 24 - 1)) group 1 604 + check_err $? "Failed to configure sampling rule with max rate" 605 + 606 + tc filter del dev $rp1 ingress protocol ip pref 1 handle 101 flower 607 + 608 + tc filter add dev $rp1 ingress protocol ip pref 1 handle 101 flower \ 609 + skip_sw action sample rate $((2 ** 24)) \ 610 + group 1 &> /dev/null 611 + check_fail $? "Managed to configure sampling rate above maximum" 612 + 613 + log_test "tc sample (w/ flower) maximum rate" 487 614 } 488 615 489 616 trap cleanup EXIT