aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/batman-adv/soft-interface.c
diff options
context:
space:
mode:
authorSimon Wunderlich <siwu@hrz.tu-chemnitz.de>2010-01-02 05:30:48 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2010-03-03 19:42:36 -0500
commite70171957a3ac67fd62af0c66efe7b7749121899 (patch)
treeec02d2965afac6384ab0fd29607c4062f93bf134 /drivers/staging/batman-adv/soft-interface.c
parentc4bf05d3960981a4291bcc9580f3d73eb4dcbe84 (diff)
Staging: batman-adv: receive packets directly using skbs
This patch removes the (ugly and racy) packet receiving thread and the kernel socket usage. Instead, packets are received directly by registering the ethernet type and handling skbs instead of self-allocated buffers. Some consequences and comments: * we don't copy the payload data when forwarding/sending/receiving data anymore. This should boost performance. * packets from/to different interfaces can be (theoretically) processed simultaneously. Only the big originator hash lock might be in the way. * no more polling or sleeping/wakeup/scheduling issues when receiving packets * this might introduce new race conditions. * aggregation and vis code still use packet buffers and are not (yet) converted. * all spinlocks were converted to irqsave/restore versions to solve some lifelock issues when preempted. This might be overkill, some of these locks might be reverted later. * skb copies are only done if neccesary to avoid overhead performance differences: * we made some "benchmarks" with intel laptops. * bandwidth on Gigabit Ethernet increased from ~500 MBit/s to ~920 MBit/s * ping latency decresed from ~2ms to ~0.2 ms I did some tests on my 9 node qemu environment and could confirm that usual sending/receiving, forwarding, vis, batctl ping etc works. Signed-off-by: Simon Wunderlich <siwu@hrz.tu-chemnitz.de> Acked-by: Sven Eckelmann <sven.eckelmann@gmx.de> Acked-by: Marek Lindner <lindner_marek@yahoo.de> Acked-by: Linus Lüssing <linus.luessing@web.de> Signed-off-by: Andrew Lunn <andrew@lunn.ch> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/staging/batman-adv/soft-interface.c')
-rw-r--r--drivers/staging/batman-adv/soft-interface.c76
1 files changed, 38 insertions, 38 deletions
diff --git a/drivers/staging/batman-adv/soft-interface.c b/drivers/staging/batman-adv/soft-interface.c
index 168a4e195a1..8ae3483a625 100644
--- a/drivers/staging/batman-adv/soft-interface.c
+++ b/drivers/staging/batman-adv/soft-interface.c
@@ -34,7 +34,6 @@ static uint16_t bcast_seqno = 1; /* give own bcast messages seq numbers to avoid
34 * broadcast storms */ 34 * broadcast storms */
35static int32_t skb_packets; 35static int32_t skb_packets;
36static int32_t skb_bad_packets; 36static int32_t skb_bad_packets;
37static int32_t lock_dropped;
38 37
39unsigned char mainIfAddr[ETH_ALEN]; 38unsigned char mainIfAddr[ETH_ALEN];
40static unsigned char mainIfAddr_default[ETH_ALEN]; 39static unsigned char mainIfAddr_default[ETH_ALEN];
@@ -67,12 +66,12 @@ int main_if_was_up(void)
67 return (memcmp(mainIfAddr, mainIfAddr_default, ETH_ALEN) != 0 ? 1 : 0); 66 return (memcmp(mainIfAddr, mainIfAddr_default, ETH_ALEN) != 0 ? 1 : 0);
68} 67}
69 68
70static int my_skb_push(struct sk_buff *skb, unsigned int len) 69int my_skb_push(struct sk_buff *skb, unsigned int len)
71{ 70{
72 int result = 0; 71 int result = 0;
73 72
74 skb_packets++; 73 skb_packets++;
75 if (skb->data - len < skb->head) { 74 if (skb_headroom(skb) < len) {
76 skb_bad_packets++; 75 skb_bad_packets++;
77 result = pskb_expand_head(skb, len, 0, GFP_ATOMIC); 76 result = pskb_expand_head(skb, len, 0, GFP_ATOMIC);
78 77
@@ -169,7 +168,10 @@ int interface_tx(struct sk_buff *skb, struct net_device *dev)
169 struct orig_node *orig_node; 168 struct orig_node *orig_node;
170 struct ethhdr *ethhdr = (struct ethhdr *)skb->data; 169 struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
171 struct bat_priv *priv = netdev_priv(dev); 170 struct bat_priv *priv = netdev_priv(dev);
171 struct batman_if *batman_if;
172 uint8_t dstaddr[6];
172 int data_len = skb->len; 173 int data_len = skb->len;
174 unsigned long flags;
173 175
174 if (atomic_read(&module_state) != MODULE_ACTIVE) 176 if (atomic_read(&module_state) != MODULE_ACTIVE)
175 goto dropped; 177 goto dropped;
@@ -185,7 +187,6 @@ int interface_tx(struct sk_buff *skb, struct net_device *dev)
185 goto dropped; 187 goto dropped;
186 188
187 bcast_packet = (struct bcast_packet *)skb->data; 189 bcast_packet = (struct bcast_packet *)skb->data;
188
189 bcast_packet->version = COMPAT_VERSION; 190 bcast_packet->version = COMPAT_VERSION;
190 191
191 /* batman packet type: broadcast */ 192 /* batman packet type: broadcast */
@@ -194,27 +195,21 @@ int interface_tx(struct sk_buff *skb, struct net_device *dev)
194 /* hw address of first interface is the orig mac because only 195 /* hw address of first interface is the orig mac because only
195 * this mac is known throughout the mesh */ 196 * this mac is known throughout the mesh */
196 memcpy(bcast_packet->orig, mainIfAddr, ETH_ALEN); 197 memcpy(bcast_packet->orig, mainIfAddr, ETH_ALEN);
198
197 /* set broadcast sequence number */ 199 /* set broadcast sequence number */
198 bcast_packet->seqno = htons(bcast_seqno); 200 bcast_packet->seqno = htons(bcast_seqno);
199 201
200 bcast_seqno++; 202 bcast_seqno++;
201 203
202 /* broadcast packet */ 204 /* broadcast packet */
203 add_bcast_packet_to_list(skb->data, skb->len); 205 add_bcast_packet_to_list(skb);
206 /* a copy is stored in the bcast list, therefore removing
207 * the original skb. */
208 kfree_skb(skb);
204 209
205 /* unicast packet */ 210 /* unicast packet */
206 } else { 211 } else {
207 212 spin_lock_irqsave(&orig_hash_lock, flags);
208 /* simply spin_lock()ing can deadlock when the lock is already
209 * hold. */
210 /* TODO: defer the work in a working queue instead of
211 * dropping */
212 if (!spin_trylock(&orig_hash_lock)) {
213 lock_dropped++;
214 printk(KERN_WARNING "batman-adv:%d packets dropped because lock was hold\n", lock_dropped);
215 goto dropped;
216 }
217
218 /* get routing information */ 213 /* get routing information */
219 orig_node = ((struct orig_node *)hash_find(orig_hash, 214 orig_node = ((struct orig_node *)hash_find(orig_hash,
220 ethhdr->h_dest)); 215 ethhdr->h_dest));
@@ -243,14 +238,17 @@ int interface_tx(struct sk_buff *skb, struct net_device *dev)
243 if (orig_node->batman_if->if_active != IF_ACTIVE) 238 if (orig_node->batman_if->if_active != IF_ACTIVE)
244 goto unlock; 239 goto unlock;
245 240
246 send_raw_packet(skb->data, skb->len, 241 /* don't lock while sending the packets ... we therefore
247 orig_node->batman_if, 242 * copy the required data before sending */
248 orig_node->router->addr); 243
244 batman_if = orig_node->batman_if;
245 memcpy(dstaddr, orig_node->router->addr, ETH_ALEN);
246 spin_unlock_irqrestore(&orig_hash_lock, flags);
247
248 send_skb_packet(skb, batman_if, dstaddr);
249 } else { 249 } else {
250 goto unlock; 250 goto unlock;
251 } 251 }
252
253 spin_unlock(&orig_hash_lock);
254 } 252 }
255 253
256 priv->stats.tx_packets++; 254 priv->stats.tx_packets++;
@@ -258,42 +256,44 @@ int interface_tx(struct sk_buff *skb, struct net_device *dev)
258 goto end; 256 goto end;
259 257
260unlock: 258unlock:
261 spin_unlock(&orig_hash_lock); 259 spin_unlock_irqrestore(&orig_hash_lock, flags);
262dropped: 260dropped:
263 priv->stats.tx_dropped++; 261 priv->stats.tx_dropped++;
264end: 262end:
265 kfree_skb(skb);
266 return 0; 263 return 0;
267} 264}
268 265
269void interface_rx(struct net_device *dev, void *packet, int packet_len) 266void interface_rx(struct sk_buff *skb, int hdr_size)
270{ 267{
271 struct sk_buff *skb; 268 struct net_device *dev = soft_device;
272 struct bat_priv *priv = netdev_priv(dev); 269 struct bat_priv *priv = netdev_priv(dev);
273 270
274 skb = dev_alloc_skb(packet_len); 271 /* check if enough space is available for pulling, and pull */
275 272 if (!pskb_may_pull(skb, hdr_size)) {
276 if (!skb) { 273 kfree_skb(skb);
277 priv->stats.rx_dropped++; 274 return;
278 goto out;
279 } 275 }
276 skb_pull_rcsum(skb, hdr_size);
277/* skb_set_mac_header(skb, -sizeof(struct ethhdr));*/
280 278
281 memcpy(skb_put(skb, packet_len), packet, packet_len);
282
283 /* Write metadata, and then pass to the receive level */
284 skb->dev = dev; 279 skb->dev = dev;
285 skb->protocol = eth_type_trans(skb, dev); 280 skb->protocol = eth_type_trans(skb, dev);
286 skb->ip_summed = CHECKSUM_UNNECESSARY; 281
282 /* should not be neccesary anymore as we use skb_pull_rcsum()
283 * TODO: please verify this and remove this TODO
284 * -- Dec 21st 2009, Simon Wunderlich */
285
286/* skb->ip_summed = CHECKSUM_UNNECESSARY;*/
287
288 /* TODO: set skb->pkt_type to PACKET_BROADCAST, PACKET_MULTICAST,
289 * PACKET_OTHERHOST or PACKET_HOST */
287 290
288 priv->stats.rx_packets++; 291 priv->stats.rx_packets++;
289 priv->stats.rx_bytes += packet_len; 292 priv->stats.rx_bytes += skb->len;
290 293
291 dev->last_rx = jiffies; 294 dev->last_rx = jiffies;
292 295
293 netif_rx(skb); 296 netif_rx(skb);
294
295out:
296 return;
297} 297}
298 298
299/* ethtool */ 299/* ethtool */