1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2 /* Copyright (c) 2020 Mellanox Technologies. */
4 #include <linux/refcount.h>
5 #include <linux/list.h>
6 #include <linux/rculist.h>
7 #include <linux/rtnetlink.h>
8 #include <linux/workqueue.h>
9 #include <linux/spinlock.h>
10 #include <linux/notifier.h>
11 #include <net/netevent.h>
17 #include "diag/en_rep_tracepoint.h"
19 static unsigned long mlx5e_rep_ipv6_interval(void)
21 if (IS_ENABLED(CONFIG_IPV6) && ipv6_stub->nd_tbl)
22 return NEIGH_VAR(&ipv6_stub->nd_tbl->parms, DELAY_PROBE_TIME);
27 static void mlx5e_rep_neigh_update_init_interval(struct mlx5e_rep_priv *rpriv)
29 unsigned long ipv4_interval = NEIGH_VAR(&arp_tbl.parms, DELAY_PROBE_TIME);
30 unsigned long ipv6_interval = mlx5e_rep_ipv6_interval();
31 struct net_device *netdev = rpriv->netdev;
32 struct mlx5e_priv *priv = netdev_priv(netdev);
34 rpriv->neigh_update.min_interval = min_t(unsigned long, ipv6_interval, ipv4_interval);
35 mlx5_fc_update_sampling_interval(priv->mdev, rpriv->neigh_update.min_interval);
38 void mlx5e_rep_queue_neigh_stats_work(struct mlx5e_priv *priv)
40 struct mlx5e_rep_priv *rpriv = priv->ppriv;
41 struct mlx5e_neigh_update_table *neigh_update = &rpriv->neigh_update;
43 mlx5_fc_queue_stats_work(priv->mdev,
44 &neigh_update->neigh_stats_work,
45 neigh_update->min_interval);
48 static bool mlx5e_rep_neigh_entry_hold(struct mlx5e_neigh_hash_entry *nhe)
50 return refcount_inc_not_zero(&nhe->refcnt);
53 static void mlx5e_rep_neigh_entry_remove(struct mlx5e_neigh_hash_entry *nhe);
55 void mlx5e_rep_neigh_entry_release(struct mlx5e_neigh_hash_entry *nhe)
57 if (refcount_dec_and_test(&nhe->refcnt)) {
58 mlx5e_rep_neigh_entry_remove(nhe);
63 static struct mlx5e_neigh_hash_entry *
64 mlx5e_get_next_nhe(struct mlx5e_rep_priv *rpriv,
65 struct mlx5e_neigh_hash_entry *nhe)
67 struct mlx5e_neigh_hash_entry *next = NULL;
72 list_next_or_null_rcu(&rpriv->neigh_update.neigh_list,
74 struct mlx5e_neigh_hash_entry,
76 list_first_or_null_rcu(&rpriv->neigh_update.neigh_list,
77 struct mlx5e_neigh_hash_entry,
80 next = list_next_or_null_rcu(&rpriv->neigh_update.neigh_list,
82 struct mlx5e_neigh_hash_entry,
84 if (mlx5e_rep_neigh_entry_hold(next))
90 mlx5e_rep_neigh_entry_release(nhe);
95 static void mlx5e_rep_neigh_stats_work(struct work_struct *work)
97 struct mlx5e_rep_priv *rpriv = container_of(work, struct mlx5e_rep_priv,
98 neigh_update.neigh_stats_work.work);
99 struct net_device *netdev = rpriv->netdev;
100 struct mlx5e_priv *priv = netdev_priv(netdev);
101 struct mlx5e_neigh_hash_entry *nhe = NULL;
104 if (!list_empty(&rpriv->neigh_update.neigh_list))
105 mlx5e_rep_queue_neigh_stats_work(priv);
107 while ((nhe = mlx5e_get_next_nhe(rpriv, nhe)) != NULL)
108 mlx5e_tc_update_neigh_used_value(nhe);
113 struct neigh_update_work {
114 struct work_struct work;
116 struct mlx5e_neigh_hash_entry *nhe;
119 static void mlx5e_release_neigh_update_work(struct neigh_update_work *update_work)
121 neigh_release(update_work->n);
122 mlx5e_rep_neigh_entry_release(update_work->nhe);
126 static void mlx5e_rep_neigh_update(struct work_struct *work)
128 struct neigh_update_work *update_work = container_of(work, struct neigh_update_work,
130 struct mlx5e_neigh_hash_entry *nhe = update_work->nhe;
131 struct neighbour *n = update_work->n;
132 bool neigh_connected, same_dev;
133 struct mlx5e_encap_entry *e;
134 unsigned char ha[ETH_ALEN];
135 struct mlx5e_priv *priv;
140 /* If these parameters are changed after we release the lock,
141 * we'll receive another event letting us know about it.
142 * We use this lock to avoid inconsistency between the neigh validity
143 * and it's hw address.
145 read_lock_bh(&n->lock);
146 memcpy(ha, n->ha, ETH_ALEN);
147 nud_state = n->nud_state;
149 same_dev = READ_ONCE(nhe->neigh_dev) == n->dev;
150 read_unlock_bh(&n->lock);
152 neigh_connected = (nud_state & NUD_VALID) && !dead;
154 trace_mlx5e_rep_neigh_update(nhe, ha, neigh_connected);
159 list_for_each_entry(e, &nhe->encap_list, encap_list) {
160 if (!mlx5e_encap_take(e))
163 priv = netdev_priv(e->out_dev);
164 mlx5e_rep_update_flows(priv, e, neigh_connected, ha);
165 mlx5e_encap_put(priv, e);
169 mlx5e_release_neigh_update_work(update_work);
172 static struct neigh_update_work *mlx5e_alloc_neigh_update_work(struct mlx5e_priv *priv,
175 struct neigh_update_work *update_work;
176 struct mlx5e_neigh_hash_entry *nhe;
177 struct mlx5e_neigh m_neigh = {};
179 update_work = kzalloc(sizeof(*update_work), GFP_ATOMIC);
180 if (WARN_ON(!update_work))
183 m_neigh.family = n->ops->family;
184 memcpy(&m_neigh.dst_ip, n->primary_key, n->tbl->key_len);
186 /* Obtain reference to nhe as last step in order not to release it in
190 nhe = mlx5e_rep_neigh_entry_lookup(priv, &m_neigh);
197 INIT_WORK(&update_work->work, mlx5e_rep_neigh_update);
200 update_work->nhe = nhe;
205 static int mlx5e_rep_netevent_event(struct notifier_block *nb,
206 unsigned long event, void *ptr)
208 struct mlx5e_rep_priv *rpriv = container_of(nb, struct mlx5e_rep_priv,
209 neigh_update.netevent_nb);
210 struct mlx5e_neigh_update_table *neigh_update = &rpriv->neigh_update;
211 struct net_device *netdev = rpriv->netdev;
212 struct mlx5e_priv *priv = netdev_priv(netdev);
213 struct mlx5e_neigh_hash_entry *nhe = NULL;
214 struct neigh_update_work *update_work;
215 struct neigh_parms *p;
220 case NETEVENT_NEIGH_UPDATE:
222 #if IS_ENABLED(CONFIG_IPV6)
223 if (n->tbl != ipv6_stub->nd_tbl && n->tbl != &arp_tbl)
225 if (n->tbl != &arp_tbl)
229 update_work = mlx5e_alloc_neigh_update_work(priv, n);
233 queue_work(priv->wq, &update_work->work);
236 case NETEVENT_DELAY_PROBE_TIME_UPDATE:
239 /* We check the device is present since we don't care about
240 * changes in the default table, we only care about changes
241 * done per device delay prob time parameter.
243 #if IS_ENABLED(CONFIG_IPV6)
244 if (!p->dev || (p->tbl != ipv6_stub->nd_tbl && p->tbl != &arp_tbl))
246 if (!p->dev || p->tbl != &arp_tbl)
251 list_for_each_entry_rcu(nhe, &neigh_update->neigh_list,
253 if (p->dev == READ_ONCE(nhe->neigh_dev)) {
262 neigh_update->min_interval = min_t(unsigned long,
263 NEIGH_VAR(p, DELAY_PROBE_TIME),
264 neigh_update->min_interval);
265 mlx5_fc_update_sampling_interval(priv->mdev,
266 neigh_update->min_interval);
272 static const struct rhashtable_params mlx5e_neigh_ht_params = {
273 .head_offset = offsetof(struct mlx5e_neigh_hash_entry, rhash_node),
274 .key_offset = offsetof(struct mlx5e_neigh_hash_entry, m_neigh),
275 .key_len = sizeof(struct mlx5e_neigh),
276 .automatic_shrinking = true,
279 int mlx5e_rep_neigh_init(struct mlx5e_rep_priv *rpriv)
281 struct mlx5e_neigh_update_table *neigh_update = &rpriv->neigh_update;
284 err = rhashtable_init(&neigh_update->neigh_ht, &mlx5e_neigh_ht_params);
288 INIT_LIST_HEAD(&neigh_update->neigh_list);
289 mutex_init(&neigh_update->encap_lock);
290 INIT_DELAYED_WORK(&neigh_update->neigh_stats_work,
291 mlx5e_rep_neigh_stats_work);
292 mlx5e_rep_neigh_update_init_interval(rpriv);
294 neigh_update->netevent_nb.notifier_call = mlx5e_rep_netevent_event;
295 err = register_netevent_notifier(&neigh_update->netevent_nb);
301 neigh_update->netevent_nb.notifier_call = NULL;
302 rhashtable_destroy(&neigh_update->neigh_ht);
304 netdev_warn(rpriv->netdev,
305 "Failed to initialize neighbours handling for vport %d\n",
310 void mlx5e_rep_neigh_cleanup(struct mlx5e_rep_priv *rpriv)
312 struct mlx5e_neigh_update_table *neigh_update = &rpriv->neigh_update;
313 struct mlx5e_priv *priv = netdev_priv(rpriv->netdev);
315 if (!rpriv->neigh_update.netevent_nb.notifier_call)
318 unregister_netevent_notifier(&neigh_update->netevent_nb);
320 flush_workqueue(priv->wq); /* flush neigh update works */
322 cancel_delayed_work_sync(&rpriv->neigh_update.neigh_stats_work);
324 mutex_destroy(&neigh_update->encap_lock);
325 rhashtable_destroy(&neigh_update->neigh_ht);
328 static int mlx5e_rep_neigh_entry_insert(struct mlx5e_priv *priv,
329 struct mlx5e_neigh_hash_entry *nhe)
331 struct mlx5e_rep_priv *rpriv = priv->ppriv;
334 err = rhashtable_insert_fast(&rpriv->neigh_update.neigh_ht,
336 mlx5e_neigh_ht_params);
340 list_add_rcu(&nhe->neigh_list, &rpriv->neigh_update.neigh_list);
345 static void mlx5e_rep_neigh_entry_remove(struct mlx5e_neigh_hash_entry *nhe)
347 struct mlx5e_rep_priv *rpriv = nhe->priv->ppriv;
349 mutex_lock(&rpriv->neigh_update.encap_lock);
351 list_del_rcu(&nhe->neigh_list);
353 rhashtable_remove_fast(&rpriv->neigh_update.neigh_ht,
355 mlx5e_neigh_ht_params);
356 mutex_unlock(&rpriv->neigh_update.encap_lock);
359 /* This function must only be called under the representor's encap_lock or
360 * inside rcu read lock section.
362 struct mlx5e_neigh_hash_entry *
363 mlx5e_rep_neigh_entry_lookup(struct mlx5e_priv *priv,
364 struct mlx5e_neigh *m_neigh)
366 struct mlx5e_rep_priv *rpriv = priv->ppriv;
367 struct mlx5e_neigh_update_table *neigh_update = &rpriv->neigh_update;
368 struct mlx5e_neigh_hash_entry *nhe;
370 nhe = rhashtable_lookup_fast(&neigh_update->neigh_ht, m_neigh,
371 mlx5e_neigh_ht_params);
372 return nhe && mlx5e_rep_neigh_entry_hold(nhe) ? nhe : NULL;
375 int mlx5e_rep_neigh_entry_create(struct mlx5e_priv *priv,
376 struct mlx5e_neigh *m_neigh,
377 struct net_device *neigh_dev,
378 struct mlx5e_neigh_hash_entry **nhe)
382 *nhe = kzalloc(sizeof(**nhe), GFP_KERNEL);
387 memcpy(&(*nhe)->m_neigh, m_neigh, sizeof(*m_neigh));
388 spin_lock_init(&(*nhe)->encap_list_lock);
389 INIT_LIST_HEAD(&(*nhe)->encap_list);
390 refcount_set(&(*nhe)->refcnt, 1);
391 WRITE_ONCE((*nhe)->neigh_dev, neigh_dev);
393 err = mlx5e_rep_neigh_entry_insert(priv, *nhe);