History

Merge tag 'mlx5-updates-2019-08-21' of git://git.kernel.org/pub/scm/linux/kernel/git/saeed/linux

Saeed Mahameed says: ==================== mlx5 tc flow handling for concurrent execution (Part 3) This series includes updates to mlx5 ethernet and core driver: Vlad submits part 3 of 3 part series to allow TC flow handling for concurrent execution. Vlad says: ========== Structure mlx5e_neigh_hash_entry code that uses it are refactored in following ways: - Extend neigh_hash_entry with rcu and modify its users to always take reference to the structure when using it (neigh_hash_entry has already had atomic reference counter which was only used when scheduling neigh update on workqueue from atomic context of neigh update netevent). - Always use mlx5e_neigh_update_table->encap_lock when modifying neigh update hash table and list. Originally, this lock was only used to synchronize with netevent handler function, which is called from bh context and cannot use rtnl lock for synchronization. Use rcu read lock instead of encap_lock to lookup nhe in atomic context of netevent even handler function. Convert encap_lock to mutex to allow creating new neigh hash entries while holding it, which is safe to do because the lock is no longer used in atomic context. - Rcu-ify mlx5e_neigh_hash_entry->encap_list by changing operations on encap list to their rcu counterparts and extending encap structure with rcu_head to free the encap instances after rcu grace period. This allows fast traversal of list of encaps attached to nhe under rcu read lock protection. - Take encap_table_lock when accessing encap entries in neigh update and neigh stats update code to protect from concurrent encap entry insertion or removal. This approach leads to potential race condition when neigh update and neigh stats update code can access encap and flow entries that are not fully initialized or are being destroyed, or neigh can change state without updating encaps that are created concurrently. Prevent these issues by following changes in flow and encap initialization: - Extend mlx5e_tc_flow with 'init_done' completion. Modify neigh update to wait for both encap and flow completions to prevent concurrent access to a structure that is being initialized by tc. - Skip structures that failed during initialization: encaps with encap_id<0 and flows that don't have OFFLOADED flag set. - To ensure that no new flows are added to encap when it is being accessed by neigh update or neigh stats update, take encap_table_lock mutex. - To prevent concurrent deletion by tc, ensure that neigh update and neigh stats update hold references to encap and flow instances while using them. With changes presented in this patch set it is now safe to execute tc concurrently with neigh update and neigh stats update. However, these two workqueue tasks modify same flow "tmp_list" field to store flows with reference taken in temporary list to release the references after update operation finishes and should not be executed concurrently with each other. Last 3 patches of this series provide 3 new mlx5 trace points to track mlx5 tc requests and mlx5 neigh updates. ====================

David S. Miller committed 7 years ago

Commit fed07ef2 parents 2b9b5e7 597088210 files · +545 −126Browse files

Unified · Split

10 files
  1. Documentation/networking/device_drivers/mellanox/mlx5.rst +46 −0
  2. drivers/net/ethernet/mellanox/mlx5/core/Makefile +1 −1
  3. drivers/net/ethernet/mellanox/mlx5/core/diag/en_rep_tracepoint.h +54 −0
  4. drivers/net/ethernet/mellanox/mlx5/core/diag/en_tc_tracepoint.c +58 −0
  5. drivers/net/ethernet/mellanox/mlx5/core/diag/en_tc_tracepoint.h +114 −0
  6. drivers/net/ethernet/mellanox/mlx5/core/en_rep.c +138 −86
  7. drivers/net/ethernet/mellanox/mlx5/core/en_rep.h +10 −1
  8. drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +116 −36
  9. drivers/net/ethernet/mellanox/mlx5/core/en_tc.h +7 −2
  10. include/net/flow_offload.h +1 −0
Documentation/networking/device_drivers/mellanox/mlx5.rst+46−0
@@ -12,6 +12,7 @@ Contents · 11 unmodified lines
1212 - `Enabling the driver and kconfig options`_
1313 - `Devlink info`_
1414 - `Devlink health reporters`_
15+- `mlx5 tracepoints`_
1516
1617 Enabling the driver and kconfig options
1718 ================================================
@@ -219,3 +220,48 @@ User commands examples: · 201 unmodified lines
219220 $ devlink health dump show pci/0000:82:00.1 reporter fw_fatal
220221
221222 NOTE: This command can run only on PF.
223+
224+mlx5 tracepoints
225+================
226+
227+mlx5 driver provides internal trace points for tracking and debugging using
228+kernel tracepoints interfaces (refer to Documentation/trace/ftrase.rst).
229+
230+For the list of support mlx5 events check /sys/kernel/debug/tracing/events/mlx5/
231+
232+tc and eswitch offloads tracepoints:
233+
234+- mlx5e_configure_flower: trace flower filter actions and cookies offloaded to mlx5::
235+
236+ $ echo mlx5:mlx5e_configure_flower >> /sys/kernel/debug/tracing/set_event
237+ $ cat /sys/kernel/debug/tracing/trace
238+ ...
239+ tc-6535 [019] ...1 2672.404466: mlx5e_configure_flower: cookie=0000000067874a55 actions= REDIRECT
240+
241+- mlx5e_delete_flower: trace flower filter actions and cookies deleted from mlx5::
242+
243+ $ echo mlx5:mlx5e_delete_flower >> /sys/kernel/debug/tracing/set_event
244+ $ cat /sys/kernel/debug/tracing/trace
245+ ...
246+ tc-6569 [010] .N.1 2686.379075: mlx5e_delete_flower: cookie=0000000067874a55 actions= NULL
247+
248+- mlx5e_stats_flower: trace flower stats request::
249+
250+ $ echo mlx5:mlx5e_stats_flower >> /sys/kernel/debug/tracing/set_event
251+ $ cat /sys/kernel/debug/tracing/trace
252+ ...
253+ tc-6546 [010] ...1 2679.704889: mlx5e_stats_flower: cookie=0000000060eb3d6a bytes=0 packets=0 lastused=4295560217
254+
255+- mlx5e_tc_update_neigh_used_value: trace tunnel rule neigh update value offloaded to mlx5::
256+
257+ $ echo mlx5:mlx5e_tc_update_neigh_used_value >> /sys/kernel/debug/tracing/set_event
258+ $ cat /sys/kernel/debug/tracing/trace
259+ ...
260+ kworker/u48:4-8806 [009] ...1 55117.882428: mlx5e_tc_update_neigh_used_value: netdev: ens1f0 IPv4: 1.1.1.10 IPv6: ::ffff:1.1.1.10 neigh_used=1
261+
262+- mlx5e_rep_neigh_update: trace neigh update tasks scheduled due to neigh state change events::
263+
264+ $ echo mlx5:mlx5e_rep_neigh_update >> /sys/kernel/debug/tracing/set_event
265+ $ cat /sys/kernel/debug/tracing/trace
266+ ...
267+ kworker/u48:7-2221 [009] ...1 1475.387435: mlx5e_rep_neigh_update: netdev: ens1f0 MAC: 24:8a:07:9a:17:9a IPv4: 1.1.1.10 IPv6: ::ffff:1.1.1.10 neigh_connected=1
drivers/net/ethernet/mellanox/mlx5/core/Makefile+1−1
@@ -35,7 +35,7 @@ mlx5_core-$(CONFIG_MLX5_EN_RXNFC) += en_fs_ethtool.o · 34 unmodified lines
3535 mlx5_core-$(CONFIG_MLX5_CORE_EN_DCB) += en_dcbnl.o en/port_buffer.o
3636 mlx5_core-$(CONFIG_MLX5_ESWITCH) += en_rep.o en_tc.o en/tc_tun.o lib/port_tun.o lag_mp.o \
3737 lib/geneve.o en/tc_tun_vxlan.o en/tc_tun_gre.o \
38− en/tc_tun_geneve.o
38+ en/tc_tun_geneve.o diag/en_tc_tracepoint.o
3939
4040 #
4141 # Core extra
drivers/net/ethernet/mellanox/mlx5/core/diag/en_rep_tracepoint.h+54−0
@@ -0,0 +1,54 @@
1+/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
2+/* Copyright (c) 2019 Mellanox Technologies. */
3+
4+#undef TRACE_SYSTEM
5+#define TRACE_SYSTEM mlx5
6+
7+#if !defined(_MLX5_EN_REP_TP_) || defined(TRACE_HEADER_MULTI_READ)
8+#define _MLX5_EN_REP_TP_
9+
10+#include <linux/tracepoint.h>
11+#include <linux/trace_seq.h>
12+#include "en_rep.h"
13+
14+TRACE_EVENT(mlx5e_rep_neigh_update,
15+ TP_PROTO(const struct mlx5e_neigh_hash_entry *nhe, const u8 *ha,
16+ bool neigh_connected),
17+ TP_ARGS(nhe, ha, neigh_connected),
18+ TP_STRUCT__entry(__string(devname, nhe->m_neigh.dev->name)
19+ __array(u8, ha, ETH_ALEN)
20+ __array(u8, v4, 4)
21+ __array(u8, v6, 16)
22+ __field(bool, neigh_connected)
23+ ),
24+ TP_fast_assign(const struct mlx5e_neigh *mn = &nhe->m_neigh;
25+ struct in6_addr *pin6;
26+ __be32 *p32;
27+
28+ __assign_str(devname, mn->dev->name);
29+ __entry->neigh_connected = neigh_connected;
30+ memcpy(__entry->ha, ha, ETH_ALEN);
31+
32+ p32 = (__be32 *)__entry->v4;
33+ pin6 = (struct in6_addr *)__entry->v6;
34+ if (mn->family == AF_INET) {
35+ *p32 = mn->dst_ip.v4;
36+ ipv6_addr_set_v4mapped(*p32, pin6);
37+ } else if (mn->family == AF_INET6) {
38+ *pin6 = mn->dst_ip.v6;
39+ }
40+ ),
41+ TP_printk("netdev: %s MAC: %pM IPv4: %pI4 IPv6: %pI6c neigh_connected=%d\n",
42+ __get_str(devname), __entry->ha,
43+ __entry->v4, __entry->v6, __entry->neigh_connected
44+ )
45+);
46+
47+#endif /* _MLX5_EN_REP_TP_ */
48+
49+/* This part must be outside protection */
50+#undef TRACE_INCLUDE_PATH
51+#define TRACE_INCLUDE_PATH ./diag
52+#undef TRACE_INCLUDE_FILE
53+#define TRACE_INCLUDE_FILE en_rep_tracepoint
54+#include <trace/define_trace.h>
drivers/net/ethernet/mellanox/mlx5/core/diag/en_tc_tracepoint.c+58−0
@@ -0,0 +1,58 @@
1+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2+/* Copyright (c) 2019 Mellanox Technologies. */
3+
4+#define CREATE_TRACE_POINTS
5+#include "en_tc_tracepoint.h"
6+
7+void put_ids_to_array(int *ids,
8+ const struct flow_action_entry *entries,
9+ unsigned int num)
10+{
11+ unsigned int i;
12+
13+ for (i = 0; i < num; i++)
14+ ids[i] = entries[i].id;
15+}
16+
17+#define NAME_SIZE 16
18+
19+static const char FLOWACT2STR[NUM_FLOW_ACTIONS][NAME_SIZE] = {
20+ [FLOW_ACTION_ACCEPT] = "ACCEPT",
21+ [FLOW_ACTION_DROP] = "DROP",
22+ [FLOW_ACTION_TRAP] = "TRAP",
23+ [FLOW_ACTION_GOTO] = "GOTO",
24+ [FLOW_ACTION_REDIRECT] = "REDIRECT",
25+ [FLOW_ACTION_MIRRED] = "MIRRED",
26+ [FLOW_ACTION_VLAN_PUSH] = "VLAN_PUSH",
27+ [FLOW_ACTION_VLAN_POP] = "VLAN_POP",
28+ [FLOW_ACTION_VLAN_MANGLE] = "VLAN_MANGLE",
29+ [FLOW_ACTION_TUNNEL_ENCAP] = "TUNNEL_ENCAP",
30+ [FLOW_ACTION_TUNNEL_DECAP] = "TUNNEL_DECAP",
31+ [FLOW_ACTION_MANGLE] = "MANGLE",
32+ [FLOW_ACTION_ADD] = "ADD",
33+ [FLOW_ACTION_CSUM] = "CSUM",
34+ [FLOW_ACTION_MARK] = "MARK",
35+ [FLOW_ACTION_WAKE] = "WAKE",
36+ [FLOW_ACTION_QUEUE] = "QUEUE",
37+ [FLOW_ACTION_SAMPLE] = "SAMPLE",
38+ [FLOW_ACTION_POLICE] = "POLICE",
39+ [FLOW_ACTION_CT] = "CT",
40+};
41+
42+const char *parse_action(struct trace_seq *p,
43+ int *ids,
44+ unsigned int num)
45+{
46+ const char *ret = trace_seq_buffer_ptr(p);
47+ unsigned int i;
48+
49+ for (i = 0; i < num; i++) {
50+ if (ids[i] < NUM_FLOW_ACTIONS)
51+ trace_seq_printf(p, "%s ", FLOWACT2STR[ids[i]]);
52+ else
53+ trace_seq_printf(p, "UNKNOWN ");
54+ }
55+
56+ trace_seq_putc(p, 0);
57+ return ret;
58+}
drivers/net/ethernet/mellanox/mlx5/core/diag/en_tc_tracepoint.h+114−0
@@ -0,0 +1,114 @@
1+/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
2+/* Copyright (c) 2019 Mellanox Technologies. */
3+
4+#undef TRACE_SYSTEM
5+#define TRACE_SYSTEM mlx5
6+
7+#if !defined(_MLX5_TC_TP_) || defined(TRACE_HEADER_MULTI_READ)
8+#define _MLX5_TC_TP_
9+
10+#include <linux/tracepoint.h>
11+#include <linux/trace_seq.h>
12+#include <net/flow_offload.h>
13+#include "en_rep.h"
14+
15+#define __parse_action(ids, num) parse_action(p, ids, num)
16+
17+void put_ids_to_array(int *ids,
18+ const struct flow_action_entry *entries,
19+ unsigned int num);
20+
21+const char *parse_action(struct trace_seq *p,
22+ int *ids,
23+ unsigned int num);
24+
25+DECLARE_EVENT_CLASS(mlx5e_flower_template,
26+ TP_PROTO(const struct flow_cls_offload *f),
27+ TP_ARGS(f),
28+ TP_STRUCT__entry(__field(void *, cookie)
29+ __field(unsigned int, num)
30+ __dynamic_array(int, ids, f->rule ?
31+ f->rule->action.num_entries : 0)
32+ ),
33+ TP_fast_assign(__entry->cookie = (void *)f->cookie;
34+ __entry->num = (f->rule ?
35+ f->rule->action.num_entries : 0);
36+ if (__entry->num)
37+ put_ids_to_array(__get_dynamic_array(ids),
38+ f->rule->action.entries,
39+ f->rule->action.num_entries);
40+ ),
41+ TP_printk("cookie=%p actions= %s\n",
42+ __entry->cookie, __entry->num ?
43+ __parse_action(__get_dynamic_array(ids),
44+ __entry->num) : "NULL"
45+ )
46+);
47+
48+DEFINE_EVENT(mlx5e_flower_template, mlx5e_configure_flower,
49+ TP_PROTO(const struct flow_cls_offload *f),
50+ TP_ARGS(f)
51+ );
52+
53+DEFINE_EVENT(mlx5e_flower_template, mlx5e_delete_flower,
54+ TP_PROTO(const struct flow_cls_offload *f),
55+ TP_ARGS(f)
56+ );
57+
58+TRACE_EVENT(mlx5e_stats_flower,
59+ TP_PROTO(const struct flow_cls_offload *f),
60+ TP_ARGS(f),
61+ TP_STRUCT__entry(__field(void *, cookie)
62+ __field(u64, bytes)
63+ __field(u64, packets)
64+ __field(u64, lastused)
65+ ),
66+ TP_fast_assign(__entry->cookie = (void *)f->cookie;
67+ __entry->bytes = f->stats.bytes;
68+ __entry->packets = f->stats.pkts;
69+ __entry->lastused = f->stats.lastused;
70+ ),
71+ TP_printk("cookie=%p bytes=%llu packets=%llu lastused=%llu\n",
72+ __entry->cookie, __entry->bytes,
73+ __entry->packets, __entry->lastused
74+ )
75+);
76+
77+TRACE_EVENT(mlx5e_tc_update_neigh_used_value,
78+ TP_PROTO(const struct mlx5e_neigh_hash_entry *nhe, bool neigh_used),
79+ TP_ARGS(nhe, neigh_used),
80+ TP_STRUCT__entry(__string(devname, nhe->m_neigh.dev->name)
81+ __array(u8, v4, 4)
82+ __array(u8, v6, 16)
83+ __field(bool, neigh_used)
84+ ),
85+ TP_fast_assign(const struct mlx5e_neigh *mn = &nhe->m_neigh;
86+ struct in6_addr *pin6;
87+ __be32 *p32;
88+
89+ __assign_str(devname, mn->dev->name);
90+ __entry->neigh_used = neigh_used;
91+
92+ p32 = (__be32 *)__entry->v4;
93+ pin6 = (struct in6_addr *)__entry->v6;
94+ if (mn->family == AF_INET) {
95+ *p32 = mn->dst_ip.v4;
96+ ipv6_addr_set_v4mapped(*p32, pin6);
97+ } else if (mn->family == AF_INET6) {
98+ *pin6 = mn->dst_ip.v6;
99+ }
100+ ),
101+ TP_printk("netdev: %s IPv4: %pI4 IPv6: %pI6c neigh_used=%d\n",
102+ __get_str(devname), __entry->v4, __entry->v6,
103+ __entry->neigh_used
104+ )
105+);
106+
107+#endif /* _MLX5_TC_TP_ */
108+
109+/* This part must be outside protection */
110+#undef TRACE_INCLUDE_PATH
111+#define TRACE_INCLUDE_PATH ./diag
112+#undef TRACE_INCLUDE_FILE
113+#define TRACE_INCLUDE_FILE en_tc_tracepoint
114+#include <trace/define_trace.h>
drivers/net/ethernet/mellanox/mlx5/core/en_rep.c+138−86
@@ -46,6 +46,8 @@ · 45 unmodified lines
4646 #include "en/tc_tun.h"
4747 #include "fs_core.h"
4848 #include "lib/port_tun.h"
49+#define CREATE_TRACE_POINTS
50+#include "diag/en_rep_tracepoint.h"
4951
5052 #define MLX5E_REP_PARAMS_DEF_LOG_SQ_SIZE \
5153 max(0x7, MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE)
@@ -524,47 +526,97 @@ void mlx5e_rep_queue_neigh_stats_work(struct mlx5e_priv *priv) · 472 unmodified lines
524526 neigh_update->min_interval);
525527 }
526528
529+static bool mlx5e_rep_neigh_entry_hold(struct mlx5e_neigh_hash_entry *nhe)
530+{
531+ return refcount_inc_not_zero(&nhe->refcnt);
532+}
533+
534+static void mlx5e_rep_neigh_entry_remove(struct mlx5e_neigh_hash_entry *nhe);
535+
536+static void mlx5e_rep_neigh_entry_release(struct mlx5e_neigh_hash_entry *nhe)
537+{
538+ if (refcount_dec_and_test(&nhe->refcnt)) {
539+ mlx5e_rep_neigh_entry_remove(nhe);
540+ kfree_rcu(nhe, rcu);
541+ }
542+}
543+
544+static struct mlx5e_neigh_hash_entry *
545+mlx5e_get_next_nhe(struct mlx5e_rep_priv *rpriv,
546+ struct mlx5e_neigh_hash_entry *nhe)
547+{
548+ struct mlx5e_neigh_hash_entry *next = NULL;
549+
550+ rcu_read_lock();
551+
552+ for (next = nhe ?
553+ list_next_or_null_rcu(&rpriv->neigh_update.neigh_list,
554+ &nhe->neigh_list,
555+ struct mlx5e_neigh_hash_entry,
556+ neigh_list) :
557+ list_first_or_null_rcu(&rpriv->neigh_update.neigh_list,
558+ struct mlx5e_neigh_hash_entry,
559+ neigh_list);
560+ next;
561+ next = list_next_or_null_rcu(&rpriv->neigh_update.neigh_list,
562+ &next->neigh_list,
563+ struct mlx5e_neigh_hash_entry,
564+ neigh_list))
565+ if (mlx5e_rep_neigh_entry_hold(next))
566+ break;
567+
568+ rcu_read_unlock();
569+
570+ if (nhe)
571+ mlx5e_rep_neigh_entry_release(nhe);
572+
573+ return next;
574+}
575+
527576 static void mlx5e_rep_neigh_stats_work(struct work_struct *work)
528577 {
529578 struct mlx5e_rep_priv *rpriv = container_of(work, struct mlx5e_rep_priv,
530579 neigh_update.neigh_stats_work.work);
531580 struct net_device *netdev = rpriv->netdev;
532581 struct mlx5e_priv *priv = netdev_priv(netdev);
533− struct mlx5e_neigh_hash_entry *nhe;
582+ struct mlx5e_neigh_hash_entry *nhe = NULL;
534583
535584 rtnl_lock();
536585 if (!list_empty(&rpriv->neigh_update.neigh_list))
537586 mlx5e_rep_queue_neigh_stats_work(priv);
538587
539− list_for_each_entry(nhe, &rpriv->neigh_update.neigh_list, neigh_list)
588+ while ((nhe = mlx5e_get_next_nhe(rpriv, nhe)) != NULL)
540589 mlx5e_tc_update_neigh_used_value(nhe);
541590
542591 rtnl_unlock();
543592 }
544593
545−static void mlx5e_rep_neigh_entry_hold(struct mlx5e_neigh_hash_entry *nhe)
546−{
547− refcount_inc(&nhe->refcnt);
548−}
549−
550−static void mlx5e_rep_neigh_entry_release(struct mlx5e_neigh_hash_entry *nhe)
551−{
552− if (refcount_dec_and_test(&nhe->refcnt))
553− kfree(nhe);
554−}
555−
556594 static void mlx5e_rep_update_flows(struct mlx5e_priv *priv,
557595 struct mlx5e_encap_entry *e,
558596 bool neigh_connected,
559597 unsigned char ha[ETH_ALEN])
560598 {
561599 struct ethhdr *eth = (struct ethhdr *)e->encap_header;
600+ struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
601+ bool encap_connected;
602+ LIST_HEAD(flow_list);
562603
563604 ASSERT_RTNL();
564605
606+ /* wait for encap to be fully initialized */
607+ wait_for_completion(&e->res_ready);
608+
609+ mutex_lock(&esw->offloads.encap_tbl_lock);
610+ encap_connected = !!(e->flags & MLX5_ENCAP_ENTRY_VALID);
611+ if (e->compl_result || (encap_connected == neigh_connected &&
612+ ether_addr_equal(e->h_dest, ha)))
613+ goto unlock;
614+
615+ mlx5e_take_all_encap_flows(e, &flow_list);
616+
565617 if ((e->flags & MLX5_ENCAP_ENTRY_VALID) &&
566618 (!neigh_connected || !ether_addr_equal(e->h_dest, ha)))
567− mlx5e_tc_encap_flows_del(priv, e);
619+ mlx5e_tc_encap_flows_del(priv, e, &flow_list);
568620
569621 if (neigh_connected && !(e->flags & MLX5_ENCAP_ENTRY_VALID)) {
570622 ether_addr_copy(e->h_dest, ha);
@@ -574,8 +626,11 @@ static void mlx5e_rep_update_flows(struct mlx5e_priv *priv, · 3 unmodified lines
574626 */
575627 ether_addr_copy(eth->h_source, e->route_dev->dev_addr);
576628
577− mlx5e_tc_encap_flows_add(priv, e);
629+ mlx5e_tc_encap_flows_add(priv, e, &flow_list);
578630 }
631+unlock:
632+ mutex_unlock(&esw->offloads.encap_tbl_lock);
633+ mlx5e_put_encap_flow_list(priv, &flow_list);
579634 }
580635
581636 static void mlx5e_rep_neigh_update(struct work_struct *work)
@@ -587,7 +642,6 @@ static void mlx5e_rep_neigh_update(struct work_struct *work) · 5 unmodified lines
587642 unsigned char ha[ETH_ALEN];
588643 struct mlx5e_priv *priv;
589644 bool neigh_connected;
590− bool encap_connected;
591645 u8 nud_state, dead;
592646
593647 rtnl_lock();
@@ -605,17 +659,14 @@ static void mlx5e_rep_neigh_update(struct work_struct *work) · 11 unmodified lines
605659
606660 neigh_connected = (nud_state & NUD_VALID) && !dead;
607661
662+ trace_mlx5e_rep_neigh_update(nhe, ha, neigh_connected);
663+
608664 list_for_each_entry(e, &nhe->encap_list, encap_list) {
609665 if (!mlx5e_encap_take(e))
610666 continue;
611667
612− encap_connected = !!(e->flags & MLX5_ENCAP_ENTRY_VALID);
613668 priv = netdev_priv(e->out_dev);
614−
615− if (encap_connected != neigh_connected ||
616− !ether_addr_equal(e->h_dest, ha))
617− mlx5e_rep_update_flows(priv, e, neigh_connected, ha);
618−
669+ mlx5e_rep_update_flows(priv, e, neigh_connected, ha);
619670 mlx5e_encap_put(priv, e);
620671 }
621672 mlx5e_rep_neigh_entry_release(nhe);
@@ -821,6 +872,28 @@ static int mlx5e_nic_rep_netdevice_event(struct notifier_block *nb, · 199 unmodified lines
821872 return NOTIFY_OK;
822873 }
823874
875+static void
876+mlx5e_rep_queue_neigh_update_work(struct mlx5e_priv *priv,
877+ struct mlx5e_neigh_hash_entry *nhe,
878+ struct neighbour *n)
879+{
880+ /* Take a reference to ensure the neighbour and mlx5 encap
881+ * entry won't be destructed until we drop the reference in
882+ * delayed work.
883+ */
884+ neigh_hold(n);
885+
886+ /* This assignment is valid as long as the the neigh reference
887+ * is taken
888+ */
889+ nhe->n = n;
890+
891+ if (!queue_work(priv->wq, &nhe->neigh_update_work)) {
892+ mlx5e_rep_neigh_entry_release(nhe);
893+ neigh_release(n);
894+ }
895+}
896+
824897 static struct mlx5e_neigh_hash_entry *
825898 mlx5e_rep_neigh_entry_lookup(struct mlx5e_priv *priv,
826899 struct mlx5e_neigh *m_neigh);
@@ -853,34 +926,13 @@ static int mlx5e_rep_netevent_event(struct notifier_block *nb, · 26 unmodified lines
853926 m_neigh.family = n->ops->family;
854927 memcpy(&m_neigh.dst_ip, n->primary_key, n->tbl->key_len);
855928
856− /* We are in atomic context and can't take RTNL mutex, so use
857− * spin_lock_bh to lookup the neigh table. bh is used since
858− * netevent can be called from a softirq context.
859− */
860− spin_lock_bh(&neigh_update->encap_lock);
929+ rcu_read_lock();
861930 nhe = mlx5e_rep_neigh_entry_lookup(priv, &m_neigh);
862− if (!nhe) {
863− spin_unlock_bh(&neigh_update->encap_lock);
931+ rcu_read_unlock();
932+ if (!nhe)
864933 return NOTIFY_DONE;
865− }
866−
867− /* This assignment is valid as long as the the neigh reference
868− * is taken
869− */
870− nhe->n = n;
871−
872− /* Take a reference to ensure the neighbour and mlx5 encap
873− * entry won't be destructed until we drop the reference in
874− * delayed work.
875− */
876− neigh_hold(n);
877− mlx5e_rep_neigh_entry_hold(nhe);
878934
879− if (!queue_work(priv->wq, &nhe->neigh_update_work)) {
880− mlx5e_rep_neigh_entry_release(nhe);
881− neigh_release(n);
882− }
883− spin_unlock_bh(&neigh_update->encap_lock);
935+ mlx5e_rep_queue_neigh_update_work(priv, nhe, n);
884936 break;
885937
886938 case NETEVENT_DELAY_PROBE_TIME_UPDATE:
@@ -897,19 +949,15 @@ static int mlx5e_rep_netevent_event(struct notifier_block *nb, · 10 unmodified lines
897949 #endif
898950 return NOTIFY_DONE;
899951
900− /* We are in atomic context and can't take RTNL mutex,
901− * so use spin_lock_bh to walk the neigh list and look for
902− * the relevant device. bh is used since netevent can be
903− * called from a softirq context.
904− */
905− spin_lock_bh(&neigh_update->encap_lock);
906− list_for_each_entry(nhe, &neigh_update->neigh_list, neigh_list) {
952+ rcu_read_lock();
953+ list_for_each_entry_rcu(nhe, &neigh_update->neigh_list,
954+ neigh_list) {
907955 if (p->dev == nhe->m_neigh.dev) {
908956 found = true;
909957 break;
910958 }
911959 }
912− spin_unlock_bh(&neigh_update->encap_lock);
960+ rcu_read_unlock();
913961 if (!found)
914962 return NOTIFY_DONE;
915963
@@ -940,7 +988,7 @@ static int mlx5e_rep_neigh_init(struct mlx5e_rep_priv *rpriv) · 24 unmodified lines
940988 return err;
941989
942990 INIT_LIST_HEAD(&neigh_update->neigh_list);
943− spin_lock_init(&neigh_update->encap_lock);
991+ mutex_init(&neigh_update->encap_lock);
944992 INIT_DELAYED_WORK(&neigh_update->neigh_stats_work,
945993 mlx5e_rep_neigh_stats_work);
946994 mlx5e_rep_neigh_update_init_interval(rpriv);
@@ -967,6 +1015,7 @@ static void mlx5e_rep_neigh_cleanup(struct mlx5e_rep_priv *rpriv) · 20 unmodified lines
9671015
9681016 cancel_delayed_work_sync(&rpriv->neigh_update.neigh_stats_work);
9691017
1018+ mutex_destroy(&neigh_update->encap_lock);
9701019 rhashtable_destroy(&neigh_update->neigh_ht);
9711020 }
9721021
@@ -982,28 +1031,27 @@ static int mlx5e_rep_neigh_entry_insert(struct mlx5e_priv *priv, · 9 unmodified lines
9821031 if (err)
9831032 return err;
9841033
985− list_add(&nhe->neigh_list, &rpriv->neigh_update.neigh_list);
1034+ list_add_rcu(&nhe->neigh_list, &rpriv->neigh_update.neigh_list);
9861035
9871036 return err;
9881037 }
9891038
990−static void mlx5e_rep_neigh_entry_remove(struct mlx5e_priv *priv,
991− struct mlx5e_neigh_hash_entry *nhe)
1039+static void mlx5e_rep_neigh_entry_remove(struct mlx5e_neigh_hash_entry *nhe)
9921040 {
993− struct mlx5e_rep_priv *rpriv = priv->ppriv;
1041+ struct mlx5e_rep_priv *rpriv = nhe->priv->ppriv;
9941042
995− spin_lock_bh(&rpriv->neigh_update.encap_lock);
1043+ mutex_lock(&rpriv->neigh_update.encap_lock);
9961044
997− list_del(&nhe->neigh_list);
1045+ list_del_rcu(&nhe->neigh_list);
9981046
9991047 rhashtable_remove_fast(&rpriv->neigh_update.neigh_ht,
10001048 &nhe->rhash_node,
10011049 mlx5e_neigh_ht_params);
1002− spin_unlock_bh(&rpriv->neigh_update.encap_lock);
1050+ mutex_unlock(&rpriv->neigh_update.encap_lock);
10031051 }
10041052
1005−/* This function must only be called under RTNL lock or under the
1006− * representor's encap_lock in case RTNL mutex can't be held.
1053+/* This function must only be called under the representor's encap_lock or
1054+ * inside rcu read lock section.
10071055 */
10081056 static struct mlx5e_neigh_hash_entry *
10091057 mlx5e_rep_neigh_entry_lookup(struct mlx5e_priv *priv,
@@ -1011,9 +1059,11 @@ mlx5e_rep_neigh_entry_lookup(struct mlx5e_priv *priv, · 1 unmodified line
10111059 {
10121060 struct mlx5e_rep_priv *rpriv = priv->ppriv;
10131061 struct mlx5e_neigh_update_table *neigh_update = &rpriv->neigh_update;
1062+ struct mlx5e_neigh_hash_entry *nhe;
10141063
1015− return rhashtable_lookup_fast(&neigh_update->neigh_ht, m_neigh,
1016− mlx5e_neigh_ht_params);
1064+ nhe = rhashtable_lookup_fast(&neigh_update->neigh_ht, m_neigh,
1065+ mlx5e_neigh_ht_params);
1066+ return nhe && mlx5e_rep_neigh_entry_hold(nhe) ? nhe : NULL;
10171067 }
10181068
10191069 static int mlx5e_rep_neigh_entry_create(struct mlx5e_priv *priv,
@@ -1026,8 +1076,10 @@ static int mlx5e_rep_neigh_entry_create(struct mlx5e_priv *priv, · 6 unmodified lines
10261076 if (!*nhe)
10271077 return -ENOMEM;
10281078
1079+ (*nhe)->priv = priv;
10291080 memcpy(&(*nhe)->m_neigh, &e->m_neigh, sizeof(e->m_neigh));
10301081 INIT_WORK(&(*nhe)->neigh_update_work, mlx5e_rep_neigh_update);
1082+ spin_lock_init(&(*nhe)->encap_list_lock);
10311083 INIT_LIST_HEAD(&(*nhe)->encap_list);
10321084 refcount_set(&(*nhe)->refcnt, 1);
10331085
@@ -1041,19 +1093,6 @@ out_free: · 7 unmodified lines
10411093 return err;
10421094 }
10431095
1044−static void mlx5e_rep_neigh_entry_destroy(struct mlx5e_priv *priv,
1045− struct mlx5e_neigh_hash_entry *nhe)
1046−{
1047− /* The neigh hash entry must be removed from the hash table regardless
1048− * of the reference count value, so it won't be found by the next
1049− * neigh notification call. The neigh hash entry reference count is
1050− * incremented only during creation and neigh notification calls and
1051− * protects from freeing the nhe struct.
1052− */
1053− mlx5e_rep_neigh_entry_remove(priv, nhe);
1054− mlx5e_rep_neigh_entry_release(nhe);
1055−}
1056−
10571096 int mlx5e_rep_encap_entry_attach(struct mlx5e_priv *priv,
10581097 struct mlx5e_encap_entry *e)
10591098 {
@@ -1066,16 +1105,26 @@ int mlx5e_rep_encap_entry_attach(struct mlx5e_priv *priv, · 6 unmodified lines
10661105 err = mlx5_tun_entropy_refcount_inc(tun_entropy, e->reformat_type);
10671106 if (err)
10681107 return err;
1108+
1109+ mutex_lock(&rpriv->neigh_update.encap_lock);
10691110 nhe = mlx5e_rep_neigh_entry_lookup(priv, &e->m_neigh);
10701111 if (!nhe) {
10711112 err = mlx5e_rep_neigh_entry_create(priv, e, &nhe);
10721113 if (err) {
1114+ mutex_unlock(&rpriv->neigh_update.encap_lock);
10731115 mlx5_tun_entropy_refcount_dec(tun_entropy,
10741116 e->reformat_type);
10751117 return err;
10761118 }
10771119 }
1078− list_add(&e->encap_list, &nhe->encap_list);
1120+
1121+ e->nhe = nhe;
1122+ spin_lock(&nhe->encap_list_lock);
1123+ list_add_rcu(&e->encap_list, &nhe->encap_list);
1124+ spin_unlock(&nhe->encap_list_lock);
1125+
1126+ mutex_unlock(&rpriv->neigh_update.encap_lock);
1127+
10791128 return 0;
10801129 }
10811130
@@ -1085,13 +1134,16 @@ void mlx5e_rep_encap_entry_detach(struct mlx5e_priv *priv, · 3 unmodified lines
10851134 struct mlx5e_rep_priv *rpriv = priv->ppriv;
10861135 struct mlx5_rep_uplink_priv *uplink_priv = &rpriv->uplink_priv;
10871136 struct mlx5_tun_entropy *tun_entropy = &uplink_priv->tun_entropy;
1088− struct mlx5e_neigh_hash_entry *nhe;
10891137
1090− list_del(&e->encap_list);
1091− nhe = mlx5e_rep_neigh_entry_lookup(priv, &e->m_neigh);
1138+ if (!e->nhe)
1139+ return;
1140+
1141+ spin_lock(&e->nhe->encap_list_lock);
1142+ list_del_rcu(&e->encap_list);
1143+ spin_unlock(&e->nhe->encap_list_lock);
10921144
1093− if (list_empty(&nhe->encap_list))
1094− mlx5e_rep_neigh_entry_destroy(priv, nhe);
1145+ mlx5e_rep_neigh_entry_release(e->nhe);
1146+ e->nhe = NULL;
10951147 mlx5_tun_entropy_refcount_dec(tun_entropy, e->reformat_type);
10961148 }
10971149
drivers/net/ethernet/mellanox/mlx5/core/en_rep.h+10−1
@@ -35,6 +35,7 @@ · 34 unmodified lines
3535
3636 #include <net/ip_tunnels.h>
3737 #include <linux/rhashtable.h>
38+#include <linux/mutex.h>
3839 #include "eswitch.h"
3940 #include "en.h"
4041 #include "lib/port_tun.h"
@@ -48,7 +49,7 @@ struct mlx5e_neigh_update_table { · 7 unmodified lines
4849 */
4950 struct list_head neigh_list;
5051 /* protect lookup/remove operations */
51− spinlock_t encap_lock;
52+ struct mutex encap_lock;
5253 struct notifier_block netevent_nb;
5354 struct delayed_work neigh_stats_work;
5455 unsigned long min_interval; /* jiffies */
@@ -110,6 +111,7 @@ struct mlx5e_neigh { · 55 unmodified lines
110111 struct mlx5e_neigh_hash_entry {
111112 struct rhash_head rhash_node;
112113 struct mlx5e_neigh m_neigh;
114+ struct mlx5e_priv *priv;
113115
114116 /* Save the neigh hash entry in a list on the representor in
115117 * addition to the hash table. In order to iterate easily over the
@@ -117,6 +119,8 @@ struct mlx5e_neigh_hash_entry { · 1 unmodified line
117119 */
118120 struct list_head neigh_list;
119121
122+ /* protects encap list */
123+ spinlock_t encap_list_lock;
120124 /* encap list sharing the same neigh */
121125 struct list_head encap_list;
122126
@@ -137,6 +141,8 @@ struct mlx5e_neigh_hash_entry { · 14 unmodified lines
137141 * 'used' value and avoid neigh deleting by the kernel.
138142 */
139143 unsigned long reported_lastuse;
144+
145+ struct rcu_head rcu;
140146 };
141147
142148 enum {
@@ -145,6 +151,8 @@ enum { · 2 unmodified lines
145151 };
146152
147153 struct mlx5e_encap_entry {
154+ /* attached neigh hash entry */
155+ struct mlx5e_neigh_hash_entry *nhe;
148156 /* neigh hash entry list of encaps sharing the same neigh */
149157 struct list_head encap_list;
150158 struct mlx5e_neigh m_neigh;
@@ -167,6 +175,7 @@ struct mlx5e_encap_entry { · 16 unmodified lines
167175 refcount_t refcnt;
168176 struct completion res_ready;
169177 int compl_result;
178+ struct rcu_head rcu;
170179 };
171180
172181 struct mlx5e_rep_sq {
drivers/net/ethernet/mellanox/mlx5/core/en_tc.c+116−36
@@ -56,6 +56,7 @@ · 55 unmodified lines
5656 #include "en/tc_tun.h"
5757 #include "lib/devcom.h"
5858 #include "lib/geneve.h"
59+#include "diag/en_tc_tracepoint.h"
5960
6061 struct mlx5_nic_flow_attr {
6162 u32 action;
@@ -126,8 +127,11 @@ struct mlx5e_tc_flow { · 64 unmodified lines
126127 struct list_head hairpin; /* flows sharing the same hairpin */
127128 struct list_head peer; /* flows with peer flow */
128129 struct list_head unready; /* flows not ready to be offloaded (e.g due to missing route) */
130+ int tmp_efi_index;
131+ struct list_head tmp_list; /* temporary flow list used by neigh update */
129132 refcount_t refcnt;
130133 struct rcu_head rcu_head;
134+ struct completion init_done;
131135 union {
132136 struct mlx5_esw_flow_attr esw_attr[0];
133137 struct mlx5_nic_flow_attr nic_attr[0];
@@ -1290,11 +1294,11 @@ static void mlx5e_tc_del_fdb_flow(struct mlx5e_priv *priv, · 1156 unmodified lines
12901294 }
12911295
12921296 void mlx5e_tc_encap_flows_add(struct mlx5e_priv *priv,
1293− struct mlx5e_encap_entry *e)
1297+ struct mlx5e_encap_entry *e,
1298+ struct list_head *flow_list)
12941299 {
12951300 struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
12961301 struct mlx5_esw_flow_attr slow_attr, *esw_attr;
1297− struct encap_flow_item *efi, *tmp;
12981302 struct mlx5_flow_handle *rule;
12991303 struct mlx5_flow_spec *spec;
13001304 struct mlx5e_tc_flow *flow;
@@ -1313,19 +1317,17 @@ void mlx5e_tc_encap_flows_add(struct mlx5e_priv *priv, · 12 unmodified lines
13131317 e->flags |= MLX5_ENCAP_ENTRY_VALID;
13141318 mlx5e_rep_queue_neigh_stats_work(priv);
13151319
1316− list_for_each_entry_safe(efi, tmp, &e->flows, list) {
1320+ list_for_each_entry(flow, flow_list, tmp_list) {
13171321 bool all_flow_encaps_valid = true;
13181322 int i;
13191323
1320− flow = container_of(efi, struct mlx5e_tc_flow, encaps[efi->index]);
1321− if (IS_ERR(mlx5e_flow_get(flow)))
1324+ if (!mlx5e_is_offloaded_flow(flow))
13221325 continue;
1323−
13241326 esw_attr = flow->esw_attr;
13251327 spec = &esw_attr->parse_attr->spec;
13261328
1327− esw_attr->dests[efi->index].encap_id = e->encap_id;
1328− esw_attr->dests[efi->index].flags |= MLX5_ESW_DEST_ENCAP_VALID;
1329+ esw_attr->dests[flow->tmp_efi_index].encap_id = e->encap_id;
1330+ esw_attr->dests[flow->tmp_efi_index].flags |= MLX5_ESW_DEST_ENCAP_VALID;
13291331 /* Flow can be associated with multiple encap entries.
13301332 * Before offloading the flow verify that all of them have
13311333 * a valid neighbour.
@@ -1340,63 +1342,55 @@ void mlx5e_tc_encap_flows_add(struct mlx5e_priv *priv, · 8 unmodified lines
13401342 }
13411343 /* Do not offload flows with unresolved neighbors */
13421344 if (!all_flow_encaps_valid)
1343− goto loop_cont;
1345+ continue;
13441346 /* update from slow path rule to encap rule */
13451347 rule = mlx5e_tc_offload_fdb_rules(esw, flow, spec, esw_attr);
13461348 if (IS_ERR(rule)) {
13471349 err = PTR_ERR(rule);
13481350 mlx5_core_warn(priv->mdev, "Failed to update cached encapsulation flow, %d\n",
13491351 err);
1350− goto loop_cont;
1352+ continue;
13511353 }
13521354
13531355 mlx5e_tc_unoffload_from_slow_path(esw, flow, &slow_attr);
13541356 flow->rule[0] = rule;
13551357 /* was unset when slow path rule removed */
13561358 flow_flag_set(flow, OFFLOADED);
1357−
1358−loop_cont:
1359− mlx5e_flow_put(priv, flow);
13601359 }
13611360 }
13621361
13631362 void mlx5e_tc_encap_flows_del(struct mlx5e_priv *priv,
1364− struct mlx5e_encap_entry *e)
1363+ struct mlx5e_encap_entry *e,
1364+ struct list_head *flow_list)
13651365 {
13661366 struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
13671367 struct mlx5_esw_flow_attr slow_attr;
1368− struct encap_flow_item *efi, *tmp;
13691368 struct mlx5_flow_handle *rule;
13701369 struct mlx5_flow_spec *spec;
13711370 struct mlx5e_tc_flow *flow;
13721371 int err;
13731372
1374− list_for_each_entry_safe(efi, tmp, &e->flows, list) {
1375− flow = container_of(efi, struct mlx5e_tc_flow, encaps[efi->index]);
1376− if (IS_ERR(mlx5e_flow_get(flow)))
1373+ list_for_each_entry(flow, flow_list, tmp_list) {
1374+ if (!mlx5e_is_offloaded_flow(flow))
13771375 continue;
1378−
13791376 spec = &flow->esw_attr->parse_attr->spec;
13801377
13811378 /* update from encap rule to slow path rule */
13821379 rule = mlx5e_tc_offload_to_slow_path(esw, flow, spec, &slow_attr);
13831380 /* mark the flow's encap dest as non-valid */
1384− flow->esw_attr->dests[efi->index].flags &= ~MLX5_ESW_DEST_ENCAP_VALID;
1381+ flow->esw_attr->dests[flow->tmp_efi_index].flags &= ~MLX5_ESW_DEST_ENCAP_VALID;
13851382
13861383 if (IS_ERR(rule)) {
13871384 err = PTR_ERR(rule);
13881385 mlx5_core_warn(priv->mdev, "Failed to update slow path (encap) flow, %d\n",
13891386 err);
1390− goto loop_cont;
1387+ continue;
13911388 }
13921389
13931390 mlx5e_tc_unoffload_fdb_rules(esw, flow, flow->esw_attr);
13941391 flow->rule[0] = rule;
13951392 /* was unset when fast path rule removed */
13961393 flow_flag_set(flow, OFFLOADED);
1397−
1398−loop_cont:
1399− mlx5e_flow_put(priv, flow);
14001394 }
14011395
14021396 /* we know that the encap is valid */
@@ -1412,11 +1406,84 @@ static struct mlx5_fc *mlx5e_tc_get_counter(struct mlx5e_tc_flow *flow) · 9 unmodified lines
14121406 return flow->nic_attr->counter;
14131407 }
14141408
1409+/* Takes reference to all flows attached to encap and adds the flows to
1410+ * flow_list using 'tmp_list' list_head in mlx5e_tc_flow.
1411+ */
1412+void mlx5e_take_all_encap_flows(struct mlx5e_encap_entry *e, struct list_head *flow_list)
1413+{
1414+ struct encap_flow_item *efi;
1415+ struct mlx5e_tc_flow *flow;
1416+
1417+ list_for_each_entry(efi, &e->flows, list) {
1418+ flow = container_of(efi, struct mlx5e_tc_flow, encaps[efi->index]);
1419+ if (IS_ERR(mlx5e_flow_get(flow)))
1420+ continue;
1421+ wait_for_completion(&flow->init_done);
1422+
1423+ flow->tmp_efi_index = efi->index;
1424+ list_add(&flow->tmp_list, flow_list);
1425+ }
1426+}
1427+
1428+/* Iterate over tmp_list of flows attached to flow_list head. */
1429+void mlx5e_put_encap_flow_list(struct mlx5e_priv *priv, struct list_head *flow_list)
1430+{
1431+ struct mlx5e_tc_flow *flow, *tmp;
1432+
1433+ list_for_each_entry_safe(flow, tmp, flow_list, tmp_list)
1434+ mlx5e_flow_put(priv, flow);
1435+}
1436+
1437+static struct mlx5e_encap_entry *
1438+mlx5e_get_next_valid_encap(struct mlx5e_neigh_hash_entry *nhe,
1439+ struct mlx5e_encap_entry *e)
1440+{
1441+ struct mlx5e_encap_entry *next = NULL;
1442+
1443+retry:
1444+ rcu_read_lock();
1445+
1446+ /* find encap with non-zero reference counter value */
1447+ for (next = e ?
1448+ list_next_or_null_rcu(&nhe->encap_list,
1449+ &e->encap_list,
1450+ struct mlx5e_encap_entry,
1451+ encap_list) :
1452+ list_first_or_null_rcu(&nhe->encap_list,
1453+ struct mlx5e_encap_entry,
1454+ encap_list);
1455+ next;
1456+ next = list_next_or_null_rcu(&nhe->encap_list,
1457+ &next->encap_list,
1458+ struct mlx5e_encap_entry,
1459+ encap_list))
1460+ if (mlx5e_encap_take(next))
1461+ break;
1462+
1463+ rcu_read_unlock();
1464+
1465+ /* release starting encap */
1466+ if (e)
1467+ mlx5e_encap_put(netdev_priv(e->out_dev), e);
1468+ if (!next)
1469+ return next;
1470+
1471+ /* wait for encap to be fully initialized */
1472+ wait_for_completion(&next->res_ready);
1473+ /* continue searching if encap entry is not in valid state after completion */
1474+ if (!(next->flags & MLX5_ENCAP_ENTRY_VALID)) {
1475+ e = next;
1476+ goto retry;
1477+ }
1478+
1479+ return next;
1480+}
1481+
14151482 void mlx5e_tc_update_neigh_used_value(struct mlx5e_neigh_hash_entry *nhe)
14161483 {
14171484 struct mlx5e_neigh *m_neigh = &nhe->m_neigh;
1485+ struct mlx5e_encap_entry *e = NULL;
14181486 struct mlx5e_tc_flow *flow;
1419− struct mlx5e_encap_entry *e;
14201487 struct mlx5_fc *counter;
14211488 struct neigh_table *tbl;
14221489 bool neigh_used = false;
@@ -1432,37 +1499,45 @@ void mlx5e_tc_update_neigh_used_value(struct mlx5e_neigh_hash_entry *nhe) · 9 unmodified lines
14321499 else
14331500 return;
14341501
1435− list_for_each_entry(e, &nhe->encap_list, encap_list) {
1502+ /* mlx5e_get_next_valid_encap() releases previous encap before returning
1503+ * next one.
1504+ */
1505+ while ((e = mlx5e_get_next_valid_encap(nhe, e)) != NULL) {
1506+ struct mlx5e_priv *priv = netdev_priv(e->out_dev);
14361507 struct encap_flow_item *efi, *tmp;
1508+ struct mlx5_eswitch *esw;
1509+ LIST_HEAD(flow_list);
14371510
1438− if (!(e->flags & MLX5_ENCAP_ENTRY_VALID) ||
1439− !mlx5e_encap_take(e))
1440− continue;
1441−
1511+ esw = priv->mdev->priv.eswitch;
1512+ mutex_lock(&esw->offloads.encap_tbl_lock);
14421513 list_for_each_entry_safe(efi, tmp, &e->flows, list) {
14431514 flow = container_of(efi, struct mlx5e_tc_flow,
14441515 encaps[efi->index]);
14451516 if (IS_ERR(mlx5e_flow_get(flow)))
14461517 continue;
1518+ list_add(&flow->tmp_list, &flow_list);
14471519
14481520 if (mlx5e_is_offloaded_flow(flow)) {
14491521 counter = mlx5e_tc_get_counter(flow);
14501522 lastuse = mlx5_fc_query_lastuse(counter);
14511523 if (time_after((unsigned long)lastuse, nhe->reported_lastuse)) {
1452− mlx5e_flow_put(netdev_priv(e->out_dev), flow);
14531524 neigh_used = true;
14541525 break;
14551526 }
14561527 }
1457−
1458− mlx5e_flow_put(netdev_priv(e->out_dev), flow);
14591528 }
1529+ mutex_unlock(&esw->offloads.encap_tbl_lock);
14601530
1461− mlx5e_encap_put(netdev_priv(e->out_dev), e);
1462− if (neigh_used)
1531+ mlx5e_put_encap_flow_list(priv, &flow_list);
1532+ if (neigh_used) {
1533+ /* release current encap before breaking the loop */
1534+ mlx5e_encap_put(priv, e);
14631535 break;
1536+ }
14641537 }
14651538
1539+ trace_mlx5e_tc_update_neigh_used_value(nhe, neigh_used);
1540+
14661541 if (neigh_used) {
14671542 nhe->reported_lastuse = jiffies;
14681543
@@ -1490,7 +1565,7 @@ static void mlx5e_encap_dealloc(struct mlx5e_priv *priv, struct mlx5e_encap_entr · 21 unmodified lines
14901565 }
14911566
14921567 kfree(e->encap_header);
1493− kfree(e);
1568+ kfree_rcu(e, rcu);
14941569 }
14951570
14961571 void mlx5e_encap_put(struct mlx5e_priv *priv, struct mlx5e_encap_entry *e)
@@ -3426,6 +3501,7 @@ mlx5e_alloc_flow(struct mlx5e_priv *priv, int attr_size, · 1929 unmodified lines
34263501 INIT_LIST_HEAD(&flow->mod_hdr);
34273502 INIT_LIST_HEAD(&flow->hairpin);
34283503 refcount_set(&flow->refcnt, 1);
3504+ init_completion(&flow->init_done);
34293505
34303506 *__flow = flow;
34313507 *__parse_attr = parse_attr;
@@ -3498,6 +3574,7 @@ __mlx5e_add_fdb_flow(struct mlx5e_priv *priv, · 66 unmodified lines
34983574 goto err_free;
34993575
35003576 err = mlx5e_tc_add_fdb_flow(priv, flow, extack);
3577+ complete_all(&flow->init_done);
35013578 if (err) {
35023579 if (!(err == -ENETUNREACH && mlx5_lag_is_multipath(in_mdev)))
35033580 goto err_free;
@@ -3695,6 +3772,7 @@ int mlx5e_configure_flower(struct net_device *dev, struct mlx5e_priv *priv, · 191 unmodified lines
36953772 goto out;
36963773 }
36973774
3775+ trace_mlx5e_configure_flower(f);
36983776 err = mlx5e_tc_add_flow(priv, f, flags, dev, &flow);
36993777 if (err)
37003778 goto out;
@@ -3744,6 +3822,7 @@ int mlx5e_delete_flower(struct net_device *dev, struct mlx5e_priv *priv, · 43 unmodified lines
37443822 rhashtable_remove_fast(tc_ht, &flow->node, tc_ht_params);
37453823 rcu_read_unlock();
37463824
3825+ trace_mlx5e_delete_flower(f);
37473826 mlx5e_flow_put(priv, flow);
37483827
37493828 return 0;
@@ -3813,6 +3892,7 @@ no_peer_counter: · 63 unmodified lines
38133892 mlx5_devcom_release_peer_data(devcom, MLX5_DEVCOM_ESW_OFFLOADS);
38143893 out:
38153894 flow_stats_update(&f->stats, bytes, packets, lastuse);
3895+ trace_mlx5e_stats_flower(f);
38163896 errout:
38173897 mlx5e_flow_put(priv, flow);
38183898 return err;
drivers/net/ethernet/mellanox/mlx5/core/en_tc.h+7−2
@@ -72,12 +72,17 @@ void mlx5e_tc_stats_matchall(struct mlx5e_priv *priv, · 71 unmodified lines
7272
7373 struct mlx5e_encap_entry;
7474 void mlx5e_tc_encap_flows_add(struct mlx5e_priv *priv,
75− struct mlx5e_encap_entry *e);
75+ struct mlx5e_encap_entry *e,
76+ struct list_head *flow_list);
7677 void mlx5e_tc_encap_flows_del(struct mlx5e_priv *priv,
77− struct mlx5e_encap_entry *e);
78+ struct mlx5e_encap_entry *e,
79+ struct list_head *flow_list);
7880 bool mlx5e_encap_take(struct mlx5e_encap_entry *e);
7981 void mlx5e_encap_put(struct mlx5e_priv *priv, struct mlx5e_encap_entry *e);
8082
83+void mlx5e_take_all_encap_flows(struct mlx5e_encap_entry *e, struct list_head *flow_list);
84+void mlx5e_put_encap_flow_list(struct mlx5e_priv *priv, struct list_head *flow_list);
85+
8186 struct mlx5e_neigh_hash_entry;
8287 void mlx5e_tc_update_neigh_used_value(struct mlx5e_neigh_hash_entry *nhe);
8388
include/net/flow_offload.h+1−0
@@ -138,6 +138,7 @@ enum flow_action_id { · 137 unmodified lines
138138 FLOW_ACTION_MPLS_PUSH,
139139 FLOW_ACTION_MPLS_POP,
140140 FLOW_ACTION_MPLS_MANGLE,
141+ NUM_FLOW_ACTIONS,
141142 };
142143
143144 /* This is mirroring enum pedit_header_type definition for easy mapping between

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t