17
17
#include <linux/kernel.h>
18
18
#include <linux/kref.h>
19
19
#include <linux/list.h>
20
+ #include <linux/lockdep.h>
20
21
#include <linux/netdevice.h>
21
22
#include <linux/random.h>
22
23
#include <linux/rculist.h>
23
24
#include <linux/rcupdate.h>
24
25
#include <linux/skbuff.h>
25
26
#include <linux/slab.h>
27
+ #include <linux/spinlock.h>
26
28
#include <linux/stddef.h>
27
29
#include <linux/string.h>
28
30
#include <linux/types.h>
@@ -76,6 +78,20 @@ struct batadv_orig_node *batadv_v_ogm_orig_get(struct batadv_priv *bat_priv,
76
78
return orig_node ;
77
79
}
78
80
81
+ /**
82
+ * batadv_v_ogm_start_queue_timer() - restart the OGM aggregation timer
83
+ * @hard_iface: the interface to use to send the OGM
84
+ */
85
+ static void batadv_v_ogm_start_queue_timer (struct batadv_hard_iface * hard_iface )
86
+ {
87
+ unsigned int msecs = BATADV_MAX_AGGREGATION_MS * 1000 ;
88
+
89
+ /* msecs * [0.9, 1.1] */
90
+ msecs += prandom_u32 () % (msecs / 5 ) - (msecs / 10 );
91
+ queue_delayed_work (batadv_event_workqueue , & hard_iface -> bat_v .aggr_wq ,
92
+ msecs_to_jiffies (msecs / 1000 ));
93
+ }
94
+
79
95
/**
80
96
* batadv_v_ogm_start_timer() - restart the OGM sending timer
81
97
* @bat_priv: the bat priv with all the soft interface information
@@ -115,6 +131,130 @@ static void batadv_v_ogm_send_to_if(struct sk_buff *skb,
115
131
batadv_send_broadcast_skb (skb , hard_iface );
116
132
}
117
133
134
+ /**
135
+ * batadv_v_ogm_len() - OGMv2 packet length
136
+ * @skb: the OGM to check
137
+ *
138
+ * Return: Length of the given OGMv2 packet, including tvlv length, excluding
139
+ * ethernet header length.
140
+ */
141
+ static unsigned int batadv_v_ogm_len (struct sk_buff * skb )
142
+ {
143
+ struct batadv_ogm2_packet * ogm_packet ;
144
+
145
+ ogm_packet = (struct batadv_ogm2_packet * )skb -> data ;
146
+ return BATADV_OGM2_HLEN + ntohs (ogm_packet -> tvlv_len );
147
+ }
148
+
149
+ /**
150
+ * batadv_v_ogm_queue_left() - check if given OGM still fits aggregation queue
151
+ * @skb: the OGM to check
152
+ * @hard_iface: the interface to use to send the OGM
153
+ *
154
+ * Caller needs to hold the hard_iface->bat_v.aggr_list_lock.
155
+ *
156
+ * Return: True, if the given OGMv2 packet still fits, false otherwise.
157
+ */
158
+ static bool batadv_v_ogm_queue_left (struct sk_buff * skb ,
159
+ struct batadv_hard_iface * hard_iface )
160
+ {
161
+ unsigned int max = min_t (unsigned int , hard_iface -> net_dev -> mtu ,
162
+ BATADV_MAX_AGGREGATION_BYTES );
163
+ unsigned int ogm_len = batadv_v_ogm_len (skb );
164
+
165
+ lockdep_assert_held (& hard_iface -> bat_v .aggr_list_lock );
166
+
167
+ return hard_iface -> bat_v .aggr_len + ogm_len <= max ;
168
+ }
169
+
170
+ /**
171
+ * batadv_v_ogm_aggr_list_free - free all elements in an aggregation queue
172
+ * @hard_iface: the interface holding the aggregation queue
173
+ *
174
+ * Empties the OGMv2 aggregation queue and frees all the skbs it contained.
175
+ *
176
+ * Caller needs to hold the hard_iface->bat_v.aggr_list_lock.
177
+ */
178
+ static void batadv_v_ogm_aggr_list_free (struct batadv_hard_iface * hard_iface )
179
+ {
180
+ struct sk_buff * skb ;
181
+
182
+ lockdep_assert_held (& hard_iface -> bat_v .aggr_list_lock );
183
+
184
+ while ((skb = skb_dequeue (& hard_iface -> bat_v .aggr_list )))
185
+ kfree_skb (skb );
186
+
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 );
256
+ }
257
+
118
258
/**
119
259
* batadv_v_ogm_send() - periodic worker broadcasting the own OGM
120
260
* @work: work queue item
@@ -210,7 +350,7 @@ static void batadv_v_ogm_send(struct work_struct *work)
210
350
break ;
211
351
}
212
352
213
- batadv_v_ogm_send_to_if (skb_tmp , hard_iface );
353
+ batadv_v_ogm_queue_on_if (skb_tmp , hard_iface );
214
354
batadv_hardif_put (hard_iface );
215
355
}
216
356
rcu_read_unlock ();
@@ -223,6 +363,27 @@ static void batadv_v_ogm_send(struct work_struct *work)
223
363
return ;
224
364
}
225
365
366
+ /**
367
+ * batadv_v_ogm_aggr_work() - OGM queue periodic task per interface
368
+ * @work: work queue item
369
+ *
370
+ * Emits aggregated OGM message in regular intervals.
371
+ */
372
+ void batadv_v_ogm_aggr_work (struct work_struct * work )
373
+ {
374
+ struct batadv_hard_iface_bat_v * batv ;
375
+ struct batadv_hard_iface * hard_iface ;
376
+
377
+ batv = container_of (work , struct batadv_hard_iface_bat_v , aggr_wq .work );
378
+ hard_iface = container_of (batv , struct batadv_hard_iface , bat_v );
379
+
380
+ spin_lock_bh (& hard_iface -> bat_v .aggr_list_lock );
381
+ batadv_v_ogm_aggr_send (hard_iface );
382
+ spin_unlock_bh (& hard_iface -> bat_v .aggr_list_lock );
383
+
384
+ batadv_v_ogm_start_queue_timer (hard_iface );
385
+ }
386
+
226
387
/**
227
388
* batadv_v_ogm_iface_enable() - prepare an interface for B.A.T.M.A.N. V
228
389
* @hard_iface: the interface to prepare
@@ -235,11 +396,25 @@ int batadv_v_ogm_iface_enable(struct batadv_hard_iface *hard_iface)
235
396
{
236
397
struct batadv_priv * bat_priv = netdev_priv (hard_iface -> soft_iface );
237
398
399
+ batadv_v_ogm_start_queue_timer (hard_iface );
238
400
batadv_v_ogm_start_timer (bat_priv );
239
401
240
402
return 0 ;
241
403
}
242
404
405
+ /**
406
+ * batadv_v_ogm_iface_disable() - release OGM interface private resources
407
+ * @hard_iface: interface for which the resources have to be released
408
+ */
409
+ void batadv_v_ogm_iface_disable (struct batadv_hard_iface * hard_iface )
410
+ {
411
+ cancel_delayed_work_sync (& hard_iface -> bat_v .aggr_wq );
412
+
413
+ spin_lock_bh (& hard_iface -> bat_v .aggr_list_lock );
414
+ batadv_v_ogm_aggr_list_free (hard_iface );
415
+ spin_unlock_bh (& hard_iface -> bat_v .aggr_list_lock );
416
+ }
417
+
243
418
/**
244
419
* batadv_v_ogm_primary_iface_set() - set a new primary interface
245
420
* @primary_iface: the new primary interface
@@ -382,7 +557,7 @@ static void batadv_v_ogm_forward(struct batadv_priv *bat_priv,
382
557
if_outgoing -> net_dev -> name , ntohl (ogm_forward -> throughput ),
383
558
ogm_forward -> ttl , if_incoming -> net_dev -> name );
384
559
385
- batadv_v_ogm_send_to_if (skb , if_outgoing );
560
+ batadv_v_ogm_queue_on_if (skb , if_outgoing );
386
561
387
562
out :
388
563
if (orig_ifinfo )
0 commit comments