hc
2024-10-22 8ac6c7a54ed1b98d142dce24b11c6de6a1e239a5
kernel/net/batman-adv/bat_v_ogm.c
....@@ -1,19 +1,7 @@
11 // SPDX-License-Identifier: GPL-2.0
2
-/* Copyright (C) 2013-2018 B.A.T.M.A.N. contributors:
2
+/* Copyright (C) 2013-2020 B.A.T.M.A.N. contributors:
33 *
44 * Antonio Quartulli
5
- *
6
- * This program is free software; you can redistribute it and/or
7
- * modify it under the terms of version 2 of the GNU General Public
8
- * License as published by the Free Software Foundation.
9
- *
10
- * This program is distributed in the hope that it will be useful, but
11
- * WITHOUT ANY WARRANTY; without even the implied warranty of
12
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
- * General Public License for more details.
14
- *
15
- * You should have received a copy of the GNU General Public License
16
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
175 */
186
197 #include "bat_v_ogm.h"
....@@ -32,11 +20,13 @@
3220 #include <linux/lockdep.h>
3321 #include <linux/mutex.h>
3422 #include <linux/netdevice.h>
23
+#include <linux/prandom.h>
3524 #include <linux/random.h>
3625 #include <linux/rculist.h>
3726 #include <linux/rcupdate.h>
3827 #include <linux/skbuff.h>
3928 #include <linux/slab.h>
29
+#include <linux/spinlock.h>
4030 #include <linux/stddef.h>
4131 #include <linux/string.h>
4232 #include <linux/types.h>
....@@ -58,9 +48,9 @@
5848 * @bat_priv: the bat priv with all the soft interface information
5949 * @addr: the address of the originator
6050 *
61
- * Return: the orig_node corresponding to the specified address. If such object
62
- * does not exist it is allocated here. In case of allocation failure returns
63
- * NULL.
51
+ * Return: the orig_node corresponding to the specified address. If such an
52
+ * object does not exist, it is allocated here. In case of allocation failure
53
+ * returns NULL.
6454 */
6555 struct batadv_orig_node *batadv_v_ogm_orig_get(struct batadv_priv *bat_priv,
6656 const u8 *addr)
....@@ -91,6 +81,20 @@
9181 }
9282
9383 /**
84
+ * batadv_v_ogm_start_queue_timer() - restart the OGM aggregation timer
85
+ * @hard_iface: the interface to use to send the OGM
86
+ */
87
+static void batadv_v_ogm_start_queue_timer(struct batadv_hard_iface *hard_iface)
88
+{
89
+ unsigned int msecs = BATADV_MAX_AGGREGATION_MS * 1000;
90
+
91
+ /* msecs * [0.9, 1.1] */
92
+ msecs += prandom_u32_max(msecs / 5) - (msecs / 10);
93
+ queue_delayed_work(batadv_event_workqueue, &hard_iface->bat_v.aggr_wq,
94
+ msecs_to_jiffies(msecs / 1000));
95
+}
96
+
97
+/**
9498 * batadv_v_ogm_start_timer() - restart the OGM sending timer
9599 * @bat_priv: the bat priv with all the soft interface information
96100 */
....@@ -104,7 +108,7 @@
104108 return;
105109
106110 msecs = atomic_read(&bat_priv->orig_interval) - BATADV_JITTER;
107
- msecs += prandom_u32() % (2 * BATADV_JITTER);
111
+ msecs += prandom_u32_max(2 * BATADV_JITTER);
108112 queue_delayed_work(batadv_event_workqueue, &bat_priv->bat_v.ogm_wq,
109113 msecs_to_jiffies(msecs));
110114 }
....@@ -119,14 +123,136 @@
119123 {
120124 struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
121125
122
- if (hard_iface->if_status != BATADV_IF_ACTIVE)
126
+ if (hard_iface->if_status != BATADV_IF_ACTIVE) {
127
+ kfree_skb(skb);
123128 return;
129
+ }
124130
125131 batadv_inc_counter(bat_priv, BATADV_CNT_MGMT_TX);
126132 batadv_add_counter(bat_priv, BATADV_CNT_MGMT_TX_BYTES,
127133 skb->len + ETH_HLEN);
128134
129135 batadv_send_broadcast_skb(skb, hard_iface);
136
+}
137
+
138
+/**
139
+ * batadv_v_ogm_len() - OGMv2 packet length
140
+ * @skb: the OGM to check
141
+ *
142
+ * Return: Length of the given OGMv2 packet, including tvlv length, excluding
143
+ * ethernet header length.
144
+ */
145
+static unsigned int batadv_v_ogm_len(struct sk_buff *skb)
146
+{
147
+ struct batadv_ogm2_packet *ogm_packet;
148
+
149
+ ogm_packet = (struct batadv_ogm2_packet *)skb->data;
150
+ return BATADV_OGM2_HLEN + ntohs(ogm_packet->tvlv_len);
151
+}
152
+
153
+/**
154
+ * batadv_v_ogm_queue_left() - check if given OGM still fits aggregation queue
155
+ * @skb: the OGM to check
156
+ * @hard_iface: the interface to use to send the OGM
157
+ *
158
+ * Caller needs to hold the hard_iface->bat_v.aggr_list.lock.
159
+ *
160
+ * Return: True, if the given OGMv2 packet still fits, false otherwise.
161
+ */
162
+static bool batadv_v_ogm_queue_left(struct sk_buff *skb,
163
+ struct batadv_hard_iface *hard_iface)
164
+{
165
+ unsigned int max = min_t(unsigned int, hard_iface->net_dev->mtu,
166
+ BATADV_MAX_AGGREGATION_BYTES);
167
+ unsigned int ogm_len = batadv_v_ogm_len(skb);
168
+
169
+ lockdep_assert_held(&hard_iface->bat_v.aggr_list.lock);
170
+
171
+ return hard_iface->bat_v.aggr_len + ogm_len <= max;
172
+}
173
+
174
+/**
175
+ * batadv_v_ogm_aggr_list_free - free all elements in an aggregation queue
176
+ * @hard_iface: the interface holding the aggregation queue
177
+ *
178
+ * Empties the OGMv2 aggregation queue and frees all the skbs it contains.
179
+ *
180
+ * Caller needs to hold the hard_iface->bat_v.aggr_list.lock.
181
+ */
182
+static void batadv_v_ogm_aggr_list_free(struct batadv_hard_iface *hard_iface)
183
+{
184
+ lockdep_assert_held(&hard_iface->bat_v.aggr_list.lock);
185
+
186
+ __skb_queue_purge(&hard_iface->bat_v.aggr_list);
187
+ hard_iface->bat_v.aggr_len = 0;
188
+}
189
+
190
+/**
191
+ * batadv_v_ogm_aggr_send() - flush & send aggregation queue
192
+ * @hard_iface: the interface with the aggregation queue to flush
193
+ *
194
+ * Aggregates all OGMv2 packets currently in the aggregation queue into a
195
+ * single OGMv2 packet and transmits this aggregate.
196
+ *
197
+ * The aggregation queue is empty after this call.
198
+ *
199
+ * Caller needs to hold the hard_iface->bat_v.aggr_list.lock.
200
+ */
201
+static void batadv_v_ogm_aggr_send(struct batadv_hard_iface *hard_iface)
202
+{
203
+ unsigned int aggr_len = hard_iface->bat_v.aggr_len;
204
+ struct sk_buff *skb_aggr;
205
+ unsigned int ogm_len;
206
+ struct sk_buff *skb;
207
+
208
+ lockdep_assert_held(&hard_iface->bat_v.aggr_list.lock);
209
+
210
+ if (!aggr_len)
211
+ return;
212
+
213
+ skb_aggr = dev_alloc_skb(aggr_len + ETH_HLEN + NET_IP_ALIGN);
214
+ if (!skb_aggr) {
215
+ batadv_v_ogm_aggr_list_free(hard_iface);
216
+ return;
217
+ }
218
+
219
+ skb_reserve(skb_aggr, ETH_HLEN + NET_IP_ALIGN);
220
+ skb_reset_network_header(skb_aggr);
221
+
222
+ while ((skb = __skb_dequeue(&hard_iface->bat_v.aggr_list))) {
223
+ hard_iface->bat_v.aggr_len -= batadv_v_ogm_len(skb);
224
+
225
+ ogm_len = batadv_v_ogm_len(skb);
226
+ skb_put_data(skb_aggr, skb->data, ogm_len);
227
+
228
+ consume_skb(skb);
229
+ }
230
+
231
+ batadv_v_ogm_send_to_if(skb_aggr, hard_iface);
232
+}
233
+
234
+/**
235
+ * batadv_v_ogm_queue_on_if() - queue a batman ogm on a given interface
236
+ * @skb: the OGM to queue
237
+ * @hard_iface: the interface to queue the OGM on
238
+ */
239
+static void batadv_v_ogm_queue_on_if(struct sk_buff *skb,
240
+ struct batadv_hard_iface *hard_iface)
241
+{
242
+ struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
243
+
244
+ if (!atomic_read(&bat_priv->aggregated_ogms)) {
245
+ batadv_v_ogm_send_to_if(skb, hard_iface);
246
+ return;
247
+ }
248
+
249
+ spin_lock_bh(&hard_iface->bat_v.aggr_list.lock);
250
+ if (!batadv_v_ogm_queue_left(skb, hard_iface))
251
+ batadv_v_ogm_aggr_send(hard_iface);
252
+
253
+ hard_iface->bat_v.aggr_len += batadv_v_ogm_len(skb);
254
+ __skb_queue_tail(&hard_iface->bat_v.aggr_list, skb);
255
+ spin_unlock_bh(&hard_iface->bat_v.aggr_list.lock);
130256 }
131257
132258 /**
....@@ -221,7 +347,7 @@
221347 break;
222348 }
223349
224
- batadv_v_ogm_send_to_if(skb_tmp, hard_iface);
350
+ batadv_v_ogm_queue_on_if(skb_tmp, hard_iface);
225351 batadv_hardif_put(hard_iface);
226352 }
227353 rcu_read_unlock();
....@@ -252,10 +378,31 @@
252378 }
253379
254380 /**
381
+ * batadv_v_ogm_aggr_work() - OGM queue periodic task per interface
382
+ * @work: work queue item
383
+ *
384
+ * Emits aggregated OGM messages in regular intervals.
385
+ */
386
+void batadv_v_ogm_aggr_work(struct work_struct *work)
387
+{
388
+ struct batadv_hard_iface_bat_v *batv;
389
+ struct batadv_hard_iface *hard_iface;
390
+
391
+ batv = container_of(work, struct batadv_hard_iface_bat_v, aggr_wq.work);
392
+ hard_iface = container_of(batv, struct batadv_hard_iface, bat_v);
393
+
394
+ spin_lock_bh(&hard_iface->bat_v.aggr_list.lock);
395
+ batadv_v_ogm_aggr_send(hard_iface);
396
+ spin_unlock_bh(&hard_iface->bat_v.aggr_list.lock);
397
+
398
+ batadv_v_ogm_start_queue_timer(hard_iface);
399
+}
400
+
401
+/**
255402 * batadv_v_ogm_iface_enable() - prepare an interface for B.A.T.M.A.N. V
256403 * @hard_iface: the interface to prepare
257404 *
258
- * Takes care of scheduling own OGM sending routine for this interface.
405
+ * Takes care of scheduling its own OGM sending routine for this interface.
259406 *
260407 * Return: 0 on success or a negative error code otherwise
261408 */
....@@ -263,9 +410,23 @@
263410 {
264411 struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
265412
413
+ batadv_v_ogm_start_queue_timer(hard_iface);
266414 batadv_v_ogm_start_timer(bat_priv);
267415
268416 return 0;
417
+}
418
+
419
+/**
420
+ * batadv_v_ogm_iface_disable() - release OGM interface private resources
421
+ * @hard_iface: interface for which the resources have to be released
422
+ */
423
+void batadv_v_ogm_iface_disable(struct batadv_hard_iface *hard_iface)
424
+{
425
+ cancel_delayed_work_sync(&hard_iface->bat_v.aggr_wq);
426
+
427
+ spin_lock_bh(&hard_iface->bat_v.aggr_list.lock);
428
+ batadv_v_ogm_aggr_list_free(hard_iface);
429
+ spin_unlock_bh(&hard_iface->bat_v.aggr_list.lock);
269430 }
270431
271432 /**
....@@ -297,15 +458,17 @@
297458 * @throughput: the current throughput
298459 *
299460 * Apply a penalty on the current throughput metric value based on the
300
- * characteristic of the interface where the OGM has been received. The return
301
- * value is computed as follows:
461
+ * characteristic of the interface where the OGM has been received.
462
+ *
463
+ * Initially the per hardif hop penalty is applied to the throughput. After
464
+ * that the return value is then computed as follows:
302465 * - throughput * 50% if the incoming and outgoing interface are the
303466 * same WiFi interface and the throughput is above
304467 * 1MBit/s
305468 * - throughput if the outgoing interface is the default
306469 * interface (i.e. this OGM is processed for the
307470 * internal table and not forwarded)
308
- * - throughput * hop penalty otherwise
471
+ * - throughput * node hop penalty otherwise
309472 *
310473 * Return: the penalised throughput metric.
311474 */
....@@ -314,8 +477,13 @@
314477 struct batadv_hard_iface *if_outgoing,
315478 u32 throughput)
316479 {
480
+ int if_hop_penalty = atomic_read(&if_incoming->hop_penalty);
317481 int hop_penalty = atomic_read(&bat_priv->hop_penalty);
318482 int hop_penalty_max = BATADV_TQ_MAX_VALUE;
483
+
484
+ /* Apply per hardif hop penalty */
485
+ throughput = throughput * (hop_penalty_max - if_hop_penalty) /
486
+ hop_penalty_max;
319487
320488 /* Don't apply hop penalty in default originator table. */
321489 if (if_outgoing == BATADV_IF_DEFAULT)
....@@ -414,7 +582,7 @@
414582 if_outgoing->net_dev->name, ntohl(ogm_forward->throughput),
415583 ogm_forward->ttl, if_incoming->net_dev->name);
416584
417
- batadv_v_ogm_send_to_if(skb, if_outgoing);
585
+ batadv_v_ogm_queue_on_if(skb, if_outgoing);
418586
419587 out:
420588 if (orig_ifinfo)
....@@ -689,7 +857,7 @@
689857 * batadv_v_ogm_process() - process an incoming batman v OGM
690858 * @skb: the skb containing the OGM
691859 * @ogm_offset: offset to the OGM which should be processed (for aggregates)
692
- * @if_incoming: the interface where this packet was receved
860
+ * @if_incoming: the interface where this packet was received
693861 */
694862 static void batadv_v_ogm_process(const struct sk_buff *skb, int ogm_offset,
695863 struct batadv_hard_iface *if_incoming)
....@@ -832,7 +1000,7 @@
8321000 {
8331001 struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
8341002 struct batadv_ogm2_packet *ogm_packet;
835
- struct ethhdr *ethhdr = eth_hdr(skb);
1003
+ struct ethhdr *ethhdr;
8361004 int ogm_offset;
8371005 u8 *packet_pos;
8381006 int ret = NET_RX_DROP;
....@@ -846,6 +1014,7 @@
8461014 if (!batadv_check_management_packet(skb, if_incoming, BATADV_OGM2_HLEN))
8471015 goto free_skb;
8481016
1017
+ ethhdr = eth_hdr(skb);
8491018 if (batadv_is_my_mac(bat_priv, ethhdr->h_source))
8501019 goto free_skb;
8511020