File Index
Files and directories
Sign in
FILE

bat_v_elp.c

File preview with syntax highlighting.

linux-6.19.14/net/batman-adv/bat_v_elp.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/* Copyright (C) B.A.T.M.A.N. contributors:
  3 *
  4 * Linus Lüssing, Marek Lindner
  5 */
  6
  7#include "bat_v_elp.h"
  8#include "main.h"
  9
 10#include <linux/atomic.h>
 11#include <linux/bitops.h>
 12#include <linux/byteorder/generic.h>
 13#include <linux/container_of.h>
 14#include <linux/errno.h>
 15#include <linux/etherdevice.h>
 16#include <linux/ethtool.h>
 17#include <linux/gfp.h>
 18#include <linux/if_ether.h>
 19#include <linux/jiffies.h>
 20#include <linux/kref.h>
 21#include <linux/list.h>
 22#include <linux/minmax.h>
 23#include <linux/netdevice.h>
 24#include <linux/nl80211.h>
 25#include <linux/random.h>
 26#include <linux/rculist.h>
 27#include <linux/rcupdate.h>
 28#include <linux/rtnetlink.h>
 29#include <linux/skbuff.h>
 30#include <linux/slab.h>
 31#include <linux/stddef.h>
 32#include <linux/string.h>
 33#include <linux/types.h>
 34#include <linux/workqueue.h>
 35#include <net/cfg80211.h>
 36#include <uapi/linux/batadv_packet.h>
 37
 38#include "bat_v_ogm.h"
 39#include "hard-interface.h"
 40#include "log.h"
 41#include "originator.h"
 42#include "routing.h"
 43#include "send.h"
 44
 45/**
 46 * struct batadv_v_metric_queue_entry - list of hardif neighbors which require
 47 *  and metric update
 48 */
 49struct batadv_v_metric_queue_entry {
 50	/** @hardif_neigh: hardif neighbor scheduled for metric update */
 51	struct batadv_hardif_neigh_node *hardif_neigh;
 52
 53	/** @list: list node for metric_queue */
 54	struct list_head list;
 55};
 56
 57/**
 58 * batadv_v_elp_start_timer() - restart timer for ELP periodic work
 59 * @hard_iface: the interface for which the timer has to be reset
 60 */
 61static void batadv_v_elp_start_timer(struct batadv_hard_iface *hard_iface)
 62{
 63	unsigned int msecs;
 64
 65	msecs = atomic_read(&hard_iface->bat_v.elp_interval) - BATADV_JITTER;
 66	msecs += get_random_u32_below(2 * BATADV_JITTER);
 67
 68	queue_delayed_work(batadv_event_workqueue, &hard_iface->bat_v.elp_wq,
 69			   msecs_to_jiffies(msecs));
 70}
 71
 72/**
 73 * batadv_v_elp_get_throughput() - get the throughput towards a neighbour
 74 * @neigh: the neighbour for which the throughput has to be obtained
 75 * @pthroughput: calculated throughput towards the given neighbour in multiples
 76 *  of 100kpbs (a value of '1' equals 0.1Mbps, '10' equals 1Mbps, etc).
 77 *
 78 * Return: true when value behind @pthroughput was set
 79 */
 80static bool batadv_v_elp_get_throughput(struct batadv_hardif_neigh_node *neigh,
 81					u32 *pthroughput)
 82{
 83	struct batadv_hard_iface *hard_iface = neigh->if_incoming;
 84	struct net_device *mesh_iface = hard_iface->mesh_iface;
 85	struct ethtool_link_ksettings link_settings;
 86	struct net_device *real_netdev;
 87	struct station_info sinfo;
 88	u32 throughput;
 89	int ret;
 90
 91	/* don't query throughput when no longer associated with any
 92	 * batman-adv interface
 93	 */
 94	if (!mesh_iface)
 95		return false;
 96
 97	/* if the user specified a customised value for this interface, then
 98	 * return it directly
 99	 */
100	throughput =  atomic_read(&hard_iface->bat_v.throughput_override);
101	if (throughput != 0) {
102		*pthroughput = throughput;
103		return true;
104	}
105
106	/* if this is a wireless device, then ask its throughput through
107	 * cfg80211 API
108	 */
109	if (batadv_is_wifi_hardif(hard_iface)) {
110		if (!batadv_is_cfg80211_hardif(hard_iface))
111			/* unsupported WiFi driver version */
112			goto default_throughput;
113
114		/* only use rtnl_trylock because the elp worker will be cancelled while
115		 * the rntl_lock is held. the cancel_delayed_work_sync() would otherwise
116		 * wait forever when the elp work_item was started and it is then also
117		 * trying to rtnl_lock
118		 */
119		if (!rtnl_trylock())
120			return false;
121		real_netdev = __batadv_get_real_netdev(hard_iface->net_dev);
122		rtnl_unlock();
123		if (!real_netdev)
124			goto default_throughput;
125
126		ret = cfg80211_get_station(real_netdev, neigh->addr, &sinfo);
127
128		if (!ret) {
129			/* free the TID stats immediately */
130			cfg80211_sinfo_release_content(&sinfo);
131		}
132
133		dev_put(real_netdev);
134		if (ret == -ENOENT) {
135			/* Node is not associated anymore! It would be
136			 * possible to delete this neighbor. For now set
137			 * the throughput metric to 0.
138			 */
139			*pthroughput = 0;
140			return true;
141		}
142		if (ret)
143			goto default_throughput;
144
145		if (sinfo.filled & BIT(NL80211_STA_INFO_EXPECTED_THROUGHPUT)) {
146			*pthroughput = sinfo.expected_throughput / 100;
147			return true;
148		}
149
150		/* try to estimate the expected throughput based on reported tx
151		 * rates
152		 */
153		if (sinfo.filled & BIT(NL80211_STA_INFO_TX_BITRATE)) {
154			*pthroughput = cfg80211_calculate_bitrate(&sinfo.txrate) / 3;
155			return true;
156		}
157
158		goto default_throughput;
159	}
160
161	/* only use rtnl_trylock because the elp worker will be cancelled while
162	 * the rntl_lock is held. the cancel_delayed_work_sync() would otherwise
163	 * wait forever when the elp work_item was started and it is then also
164	 * trying to rtnl_lock
165	 */
166	if (!rtnl_trylock())
167		return false;
168
169	/* if not a wifi interface, check if this device provides data via
170	 * ethtool (e.g. an Ethernet adapter)
171	 */
172	ret = __ethtool_get_link_ksettings(hard_iface->net_dev, &link_settings);
173	rtnl_unlock();
174	if (ret == 0) {
175		/* link characteristics might change over time */
176		if (link_settings.base.duplex == DUPLEX_FULL)
177			hard_iface->bat_v.flags |= BATADV_FULL_DUPLEX;
178		else
179			hard_iface->bat_v.flags &= ~BATADV_FULL_DUPLEX;
180
181		throughput = link_settings.base.speed;
182		if (throughput && throughput != SPEED_UNKNOWN) {
183			*pthroughput = throughput * 10;
184			return true;
185		}
186	}
187
188default_throughput:
189	if (!(hard_iface->bat_v.flags & BATADV_WARNING_DEFAULT)) {
190		batadv_info(mesh_iface,
191			    "WiFi driver or ethtool info does not provide information about link speeds on interface %s, therefore defaulting to hardcoded throughput values of %u.%1u Mbps. Consider overriding the throughput manually or checking your driver.\n",
192			    hard_iface->net_dev->name,
193			    BATADV_THROUGHPUT_DEFAULT_VALUE / 10,
194			    BATADV_THROUGHPUT_DEFAULT_VALUE % 10);
195		hard_iface->bat_v.flags |= BATADV_WARNING_DEFAULT;
196	}
197
198	/* if none of the above cases apply, return the base_throughput */
199	*pthroughput = BATADV_THROUGHPUT_DEFAULT_VALUE;
200	return true;
201}
202
203/**
204 * batadv_v_elp_throughput_metric_update() - worker updating the throughput
205 *  metric of a single hop neighbour
206 * @neigh: the neighbour to probe
207 */
208static void
209batadv_v_elp_throughput_metric_update(struct batadv_hardif_neigh_node *neigh)
210{
211	u32 throughput;
212	bool valid;
213
214	valid = batadv_v_elp_get_throughput(neigh, &throughput);
215	if (!valid)
216		return;
217
218	ewma_throughput_add(&neigh->bat_v.throughput, throughput);
219}
220
221/**
222 * batadv_v_elp_wifi_neigh_probe() - send link probing packets to a neighbour
223 * @neigh: the neighbour to probe
224 *
225 * Sends a predefined number of unicast wifi packets to a given neighbour in
226 * order to trigger the throughput estimation on this link by the RC algorithm.
227 * Packets are sent only if there is not enough payload unicast traffic towards
228 * this neighbour..
229 *
230 * Return: True on success and false in case of error during skb preparation.
231 */
232static bool
233batadv_v_elp_wifi_neigh_probe(struct batadv_hardif_neigh_node *neigh)
234{
235	struct batadv_hard_iface *hard_iface = neigh->if_incoming;
236	struct batadv_priv *bat_priv = netdev_priv(hard_iface->mesh_iface);
237	unsigned long last_tx_diff;
238	struct sk_buff *skb;
239	int probe_len, i;
240	int elp_skb_len;
241
242	/* this probing routine is for Wifi neighbours only */
243	if (!batadv_is_wifi_hardif(hard_iface))
244		return true;
245
246	/* probe the neighbor only if no unicast packets have been sent
247	 * to it in the last 100 milliseconds: this is the rate control
248	 * algorithm sampling interval (minstrel). In this way, if not
249	 * enough traffic has been sent to the neighbor, batman-adv can
250	 * generate 2 probe packets and push the RC algorithm to perform
251	 * the sampling
252	 */
253	last_tx_diff = jiffies_to_msecs(jiffies - neigh->bat_v.last_unicast_tx);
254	if (last_tx_diff <= BATADV_ELP_PROBE_MAX_TX_DIFF)
255		return true;
256
257	probe_len = max_t(int, sizeof(struct batadv_elp_packet),
258			  BATADV_ELP_MIN_PROBE_SIZE);
259
260	for (i = 0; i < BATADV_ELP_PROBES_PER_NODE; i++) {
261		elp_skb_len = hard_iface->bat_v.elp_skb->len;
262		skb = skb_copy_expand(hard_iface->bat_v.elp_skb, 0,
263				      probe_len - elp_skb_len,
264				      GFP_ATOMIC);
265		if (!skb)
266			return false;
267
268		/* Tell the skb to get as big as the allocated space (we want
269		 * the packet to be exactly of that size to make the link
270		 * throughput estimation effective.
271		 */
272		skb_put_zero(skb, probe_len - hard_iface->bat_v.elp_skb->len);
273
274		batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
275			   "Sending unicast (probe) ELP packet on interface %s to %pM\n",
276			   hard_iface->net_dev->name, neigh->addr);
277
278		batadv_send_skb_packet(skb, hard_iface, neigh->addr);
279	}
280
281	return true;
282}
283
284/**
285 * batadv_v_elp_periodic_work() - ELP periodic task per interface
286 * @work: work queue item
287 *
288 * Emits broadcast ELP messages in regular intervals.
289 */
290static void batadv_v_elp_periodic_work(struct work_struct *work)
291{
292	struct batadv_v_metric_queue_entry *metric_entry;
293	struct batadv_v_metric_queue_entry *metric_safe;
294	struct batadv_hardif_neigh_node *hardif_neigh;
295	struct batadv_hard_iface *hard_iface;
296	struct batadv_hard_iface_bat_v *bat_v;
297	struct batadv_elp_packet *elp_packet;
298	struct list_head metric_queue;
299	struct batadv_priv *bat_priv;
300	struct sk_buff *skb;
301	u32 elp_interval;
302
303	bat_v = container_of(work, struct batadv_hard_iface_bat_v, elp_wq.work);
304	hard_iface = container_of(bat_v, struct batadv_hard_iface, bat_v);
305	bat_priv = netdev_priv(hard_iface->mesh_iface);
306
307	if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_DEACTIVATING)
308		goto out;
309
310	/* we are in the process of shutting this interface down */
311	if (hard_iface->if_status == BATADV_IF_NOT_IN_USE ||
312	    hard_iface->if_status == BATADV_IF_TO_BE_REMOVED)
313		goto out;
314
315	/* the interface was enabled but may not be ready yet */
316	if (hard_iface->if_status != BATADV_IF_ACTIVE)
317		goto restart_timer;
318
319	skb = skb_copy(hard_iface->bat_v.elp_skb, GFP_ATOMIC);
320	if (!skb)
321		goto restart_timer;
322
323	elp_packet = (struct batadv_elp_packet *)skb->data;
324	elp_packet->seqno = htonl(atomic_read(&hard_iface->bat_v.elp_seqno));
325	elp_interval = atomic_read(&hard_iface->bat_v.elp_interval);
326	elp_packet->elp_interval = htonl(elp_interval);
327
328	batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
329		   "Sending broadcast ELP packet on interface %s, seqno %u\n",
330		   hard_iface->net_dev->name,
331		   atomic_read(&hard_iface->bat_v.elp_seqno));
332
333	batadv_send_broadcast_skb(skb, hard_iface);
334
335	atomic_inc(&hard_iface->bat_v.elp_seqno);
336
337	INIT_LIST_HEAD(&metric_queue);
338
339	/* The throughput metric is updated on each sent packet. This way, if a
340	 * node is dead and no longer sends packets, batman-adv is still able to
341	 * react timely to its death.
342	 *
343	 * The throughput metric is updated by following these steps:
344	 * 1) if the hard_iface is wifi => send a number of unicast ELPs for
345	 *    probing/sampling to each neighbor
346	 * 2) update the throughput metric value of each neighbor (note that the
347	 *    value retrieved in this step might be 100ms old because the
348	 *    probing packets at point 1) could still be in the HW queue)
349	 */
350	rcu_read_lock();
351	hlist_for_each_entry_rcu(hardif_neigh, &hard_iface->neigh_list, list) {
352		if (!batadv_v_elp_wifi_neigh_probe(hardif_neigh))
353			/* if something goes wrong while probing, better to stop
354			 * sending packets immediately and reschedule the task
355			 */
356			break;
357
358		if (!kref_get_unless_zero(&hardif_neigh->refcount))
359			continue;
360
361		/* Reading the estimated throughput from cfg80211 is a task that
362		 * may sleep and that is not allowed in an rcu protected
363		 * context. Therefore add it to metric_queue and process it
364		 * outside rcu protected context.
365		 */
366		metric_entry = kzalloc(sizeof(*metric_entry), GFP_ATOMIC);
367		if (!metric_entry) {
368			batadv_hardif_neigh_put(hardif_neigh);
369			continue;
370		}
371
372		metric_entry->hardif_neigh = hardif_neigh;
373		list_add(&metric_entry->list, &metric_queue);
374	}
375	rcu_read_unlock();
376
377	list_for_each_entry_safe(metric_entry, metric_safe, &metric_queue, list) {
378		batadv_v_elp_throughput_metric_update(metric_entry->hardif_neigh);
379
380		batadv_hardif_neigh_put(metric_entry->hardif_neigh);
381		list_del(&metric_entry->list);
382		kfree(metric_entry);
383	}
384
385restart_timer:
386	batadv_v_elp_start_timer(hard_iface);
387out:
388	return;
389}
390
391/**
392 * batadv_v_elp_iface_enable() - setup the ELP interface private resources
393 * @hard_iface: interface for which the data has to be prepared
394 *
395 * Return: 0 on success or a -ENOMEM in case of failure.
396 */
397int batadv_v_elp_iface_enable(struct batadv_hard_iface *hard_iface)
398{
399	static const size_t tvlv_padding = sizeof(__be32);
400	struct batadv_elp_packet *elp_packet;
401	unsigned char *elp_buff;
402	u32 random_seqno;
403	size_t size;
404	int res = -ENOMEM;
405
406	size = ETH_HLEN + NET_IP_ALIGN + BATADV_ELP_HLEN + tvlv_padding;
407	hard_iface->bat_v.elp_skb = dev_alloc_skb(size);
408	if (!hard_iface->bat_v.elp_skb)
409		goto out;
410
411	skb_reserve(hard_iface->bat_v.elp_skb, ETH_HLEN + NET_IP_ALIGN);
412	elp_buff = skb_put_zero(hard_iface->bat_v.elp_skb,
413				BATADV_ELP_HLEN + tvlv_padding);
414	elp_packet = (struct batadv_elp_packet *)elp_buff;
415
416	elp_packet->packet_type = BATADV_ELP;
417	elp_packet->version = BATADV_COMPAT_VERSION;
418
419	/* randomize initial seqno to avoid collision */
420	get_random_bytes(&random_seqno, sizeof(random_seqno));
421	atomic_set(&hard_iface->bat_v.elp_seqno, random_seqno);
422
423	/* assume full-duplex by default */
424	hard_iface->bat_v.flags |= BATADV_FULL_DUPLEX;
425
426	/* warn the user (again) if there is no throughput data is available */
427	hard_iface->bat_v.flags &= ~BATADV_WARNING_DEFAULT;
428
429	if (batadv_is_wifi_hardif(hard_iface))
430		hard_iface->bat_v.flags &= ~BATADV_FULL_DUPLEX;
431
432	INIT_DELAYED_WORK(&hard_iface->bat_v.elp_wq,
433			  batadv_v_elp_periodic_work);
434	batadv_v_elp_start_timer(hard_iface);
435	res = 0;
436
437out:
438	return res;
439}
440
441/**
442 * batadv_v_elp_iface_disable() - release ELP interface private resources
443 * @hard_iface: interface for which the resources have to be released
444 */
445void batadv_v_elp_iface_disable(struct batadv_hard_iface *hard_iface)
446{
447	cancel_delayed_work_sync(&hard_iface->bat_v.elp_wq);
448
449	dev_kfree_skb(hard_iface->bat_v.elp_skb);
450	hard_iface->bat_v.elp_skb = NULL;
451}
452
453/**
454 * batadv_v_elp_iface_activate() - update the ELP buffer belonging to the given
455 *  hard-interface
456 * @primary_iface: the new primary interface
457 * @hard_iface: interface holding the to-be-updated buffer
458 */
459void batadv_v_elp_iface_activate(struct batadv_hard_iface *primary_iface,
460				 struct batadv_hard_iface *hard_iface)
461{
462	struct batadv_elp_packet *elp_packet;
463	struct sk_buff *skb;
464
465	if (!hard_iface->bat_v.elp_skb)
466		return;
467
468	skb = hard_iface->bat_v.elp_skb;
469	elp_packet = (struct batadv_elp_packet *)skb->data;
470	ether_addr_copy(elp_packet->orig,
471			primary_iface->net_dev->dev_addr);
472}
473
474/**
475 * batadv_v_elp_primary_iface_set() - change internal data to reflect the new
476 *  primary interface
477 * @primary_iface: the new primary interface
478 */
479void batadv_v_elp_primary_iface_set(struct batadv_hard_iface *primary_iface)
480{
481	struct batadv_hard_iface *hard_iface;
482	struct list_head *iter;
483
484	/* update orig field of every elp iface belonging to this mesh */
485	rcu_read_lock();
486	netdev_for_each_lower_private_rcu(primary_iface->mesh_iface, hard_iface, iter)
487		batadv_v_elp_iface_activate(primary_iface, hard_iface);
488	rcu_read_unlock();
489}
490
491/**
492 * batadv_v_elp_neigh_update() - update an ELP neighbour node
493 * @bat_priv: the bat priv with all the mesh interface information
494 * @neigh_addr: the neighbour interface address
495 * @if_incoming: the interface the packet was received through
496 * @elp_packet: the received ELP packet
497 *
498 * Updates the ELP neighbour node state with the data received within the new
499 * ELP packet.
500 */
501static void batadv_v_elp_neigh_update(struct batadv_priv *bat_priv,
502				      u8 *neigh_addr,
503				      struct batadv_hard_iface *if_incoming,
504				      struct batadv_elp_packet *elp_packet)
505
506{
507	struct batadv_neigh_node *neigh;
508	struct batadv_orig_node *orig_neigh;
509	struct batadv_hardif_neigh_node *hardif_neigh;
510	s32 seqno_diff;
511	s32 elp_latest_seqno;
512
513	orig_neigh = batadv_v_ogm_orig_get(bat_priv, elp_packet->orig);
514	if (!orig_neigh)
515		return;
516
517	neigh = batadv_neigh_node_get_or_create(orig_neigh,
518						if_incoming, neigh_addr);
519	if (!neigh)
520		goto orig_free;
521
522	hardif_neigh = batadv_hardif_neigh_get(if_incoming, neigh_addr);
523	if (!hardif_neigh)
524		goto neigh_free;
525
526	elp_latest_seqno = hardif_neigh->bat_v.elp_latest_seqno;
527	seqno_diff = ntohl(elp_packet->seqno) - elp_latest_seqno;
528
529	/* known or older sequence numbers are ignored. However always adopt
530	 * if the router seems to have been restarted.
531	 */
532	if (seqno_diff < 1 && seqno_diff > -BATADV_ELP_MAX_AGE)
533		goto hardif_free;
534
535	neigh->last_seen = jiffies;
536	hardif_neigh->last_seen = jiffies;
537	hardif_neigh->bat_v.elp_latest_seqno = ntohl(elp_packet->seqno);
538	hardif_neigh->bat_v.elp_interval = ntohl(elp_packet->elp_interval);
539
540hardif_free:
541	batadv_hardif_neigh_put(hardif_neigh);
542neigh_free:
543	batadv_neigh_node_put(neigh);
544orig_free:
545	batadv_orig_node_put(orig_neigh);
546}
547
548/**
549 * batadv_v_elp_packet_recv() - main ELP packet handler
550 * @skb: the received packet
551 * @if_incoming: the interface this packet was received through
552 *
553 * Return: NET_RX_SUCCESS and consumes the skb if the packet was properly
554 * processed or NET_RX_DROP in case of failure.
555 */
556int batadv_v_elp_packet_recv(struct sk_buff *skb,
557			     struct batadv_hard_iface *if_incoming)
558{
559	struct batadv_priv *bat_priv = netdev_priv(if_incoming->mesh_iface);
560	struct batadv_elp_packet *elp_packet;
561	struct batadv_hard_iface *primary_if;
562	struct ethhdr *ethhdr;
563	bool res;
564	int ret = NET_RX_DROP;
565
566	res = batadv_check_management_packet(skb, if_incoming, BATADV_ELP_HLEN);
567	if (!res)
568		goto free_skb;
569
570	ethhdr = eth_hdr(skb);
571	if (batadv_is_my_mac(bat_priv, ethhdr->h_source))
572		goto free_skb;
573
574	/* did we receive a B.A.T.M.A.N. V ELP packet on an interface
575	 * that does not have B.A.T.M.A.N. V ELP enabled ?
576	 */
577	if (strcmp(bat_priv->algo_ops->name, "BATMAN_V") != 0)
578		goto free_skb;
579
580	elp_packet = (struct batadv_elp_packet *)skb->data;
581
582	batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
583		   "Received ELP packet from %pM seqno %u ORIG: %pM\n",
584		   ethhdr->h_source, ntohl(elp_packet->seqno),
585		   elp_packet->orig);
586
587	primary_if = batadv_primary_if_get_selected(bat_priv);
588	if (!primary_if)
589		goto free_skb;
590
591	batadv_v_elp_neigh_update(bat_priv, ethhdr->h_source, if_incoming,
592				  elp_packet);
593
594	ret = NET_RX_SUCCESS;
595	batadv_hardif_put(primary_if);
596
597free_skb:
598	if (ret == NET_RX_SUCCESS)
599		consume_skb(skb);
600	else
601		kfree_skb(skb);
602
603	return ret;
604}
~/ Read-only file preview.