From patchwork Tue Apr 30 07:33:19 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gerlando Falauto X-Patchwork-Id: 240576 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id E13AF2C00BD for ; Tue, 30 Apr 2013 17:39:09 +1000 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1758753Ab3D3HjE (ORCPT ); Tue, 30 Apr 2013 03:39:04 -0400 Received: from mail-de.keymile.com ([195.8.104.250]:56175 "EHLO mail-de.keymile.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753162Ab3D3HjD (ORCPT ); Tue, 30 Apr 2013 03:39:03 -0400 Received: from frodo.de.keymile.net ([10.9.1.54]:38433 helo=mailrelay.de.keymile.net) by mail-de.keymile.com with esmtp (Exim 4.76) (envelope-from ) id 1UX547-00035F-0c; Tue, 30 Apr 2013 09:33:31 +0200 Received: from chber1-10555x.ch.keymile.net ([172.31.40.82]) by mailrelay.de.keymile.net (8.12.2/8.12.2) with ESMTP id r3U7VYxf025823; Tue, 30 Apr 2013 09:31:38 +0200 (MEST) From: Gerlando Falauto To: netdev@vger.kernel.org Cc: jon.maloy@ericsson.com, erik.hugne@ericsson.com, ying.xue@windriver.com, holger.brunck@keymile.com, Gerlando Falauto Subject: [PATCH v3 3/3] tipc: pskb_copy() buffers when sending on more than one bearer Date: Tue, 30 Apr 2013 09:33:19 +0200 Message-Id: <1367307199-10577-3-git-send-email-gerlando.falauto@keymile.com> X-Mailer: git-send-email 1.7.10.1 In-Reply-To: <1367307199-10577-1-git-send-email-gerlando.falauto@keymile.com> References: <1367244820-29881-1-git-send-email-gerlando.falauto@keymile.com> <1367307199-10577-1-git-send-email-gerlando.falauto@keymile.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org When sending packets, TIPC bearers use skb_clone() before writing their hardware header. This will however NOT copy the data buffer. So when the same packet is sent over multiple bearers (to reach multiple nodes), the same socket buffer data will be treated by multiple tipc_media drivers which will write their own hardware header through dev_hard_header(). Most of the time this is not a problem, because by the time the packet is processed by the second media, it has already been sent over the first one. However, when the first transmission is delayed (e.g. because of insufficient bandwidth or through a shaper), the next bearer will overwrite the hardware header, resulting in the packet being sent: a) with the wrong source address, when bearers of the same type, e.g. ethernet, are involved b) with a completely corrupt header, or even dropped, when bearers of different types are involved. So when the same socket buffer is to be sent multiple times, send a pskb_copy() instead (from the second instance on), and release it afterwards (the bearer will skb_clone() it anyway). Signed-off-by: Gerlando Falauto --- Changes from v2: * Rebased net/tipc/bcast.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c index c8f572f..a8e574d 100644 --- a/net/tipc/bcast.c +++ b/net/tipc/bcast.c @@ -611,6 +611,7 @@ static int tipc_bcbearer_send(struct sk_buff *buf, struct tipc_bearer *p = bcbearer->bpairs[bp_index].primary; struct tipc_bearer *s = bcbearer->bpairs[bp_index].secondary; struct tipc_bearer *b = p; + struct sk_buff *tbuf; if (!p) break; /* No more bearers to try */ @@ -626,7 +627,17 @@ static int tipc_bcbearer_send(struct sk_buff *buf, if (bcbearer->remains_new.count == bcbearer->remains.count) continue; /* Nothing added by bearer pair */ - tipc_bearer_send(b, buf, &b->media->bcast_addr); + if (bp_index == 0) { + /* Use original buffer for first bearer */ + tipc_bearer_send(b, buf, &b->media->bcast_addr); + } else { + /* Avoid concurrent buffer access */ + tbuf = pskb_copy(buf, GFP_ATOMIC); + if (!tbuf) + break; + tipc_bearer_send(b, tbuf, &b->media->bcast_addr); + kfree_skb(tbuf); /* Bearer keeps a clone */ + } /* Swap bearers for next packet */ if (s) {