* Re: question about drivers/net/ethernet/ti/cpsw.c
From: David Miller @ 2014-09-02 1:11 UTC (permalink / raw)
To: julia.lawall; +Cc: zonque, netdev
In-Reply-To: <alpine.DEB.2.02.1408282118560.2226@localhost6.localdomain6>
From: Julia Lawall <julia.lawall@lip6.fr>
Date: Thu, 28 Aug 2014 21:26:55 +0200 (CEST)
> I wonder if the following patch:
>
> commit aa1a15e2d9199711cdcc9399fdb22544ab835a83
> Author: Daniel Mack <zonque@gmail.com>
> Date: Sat Sep 21 00:50:38 2013 +0530
>
> introduced a race condition in drivers/net/ethernet/ti/cpsw.c. I was
> looking at an old version of the file (Linux 3.10), and it has
>
> clean_irq_ret:
> for (i = 0; i < priv->num_irqs; i++)
> free_irq(priv->irqs_table[i], priv);
>
> at the beginning of the cleanup code of the probe function (cpsw_probe).
> The above patch replaces request_irq by devm_request_irq and gets rid of
> the above cleanup code. But that moves the stopping of the interrupts
> after the following code at the end of the function:
>
> free_netdev(priv->ndev);
>
> The interrupt handler (cpsw_interrupt) does reference priv->ndev:
>
> if (netif_running(priv->ndev)) {
> napi_schedule(&priv->napi);
> return IRQ_HANDLED;
> }
>
> so perhaps this could be a problem. The same happens in the remove
> function.
It could definitely be a problem.
Probably it would be better for this device to request IRQs in open
and release them in close like so many other networking drivers do.
^ permalink raw reply
* Re: [patch net-next RFC 10/12] openvswitch: add support for datapath hardware offload
From: Jamal Hadi Salim @ 2014-09-02 1:08 UTC (permalink / raw)
To: Jiri Pirko
Cc: Simon Horman, Thomas Graf, Alexei Starovoitov, Andy Gospodarek,
Roopa Prabhu, John Fastabend, Scott Feldman, netdev, David Miller,
Neil Horman, Andy Gospodarek, dborkman, ogerlitz, Jesse Gross,
Pravin Shelar, Andy Zhou, ben, Stephen Hemminger,
jeffrey.t.kirsher, vyasevic, Cong Wang, john.r.fastabend,
Eric Dumazet, Florian Fainelli, John
In-Reply-To: <20140901202851.GA1862@nanopsycho.lan>
On 09/01/14 16:28, Jiri Pirko wrote:
> Jamal, please be ensured that no one I know of is against future
> different classifiers.
>
Ok, glad to hear that.
The patches and/or some of the discussion were not projecting that
view. Even for the flow case, I am pretty sure we are going to
need a few iterations before we settle on a general consensus.
cheers,
jamal
^ permalink raw reply
* Re: pull request: wireless 2014-08-28
From: David Miller @ 2014-09-02 1:08 UTC (permalink / raw)
To: linville; +Cc: linux-wireless, netdev, linux-kernel
In-Reply-To: <20140828181713.GL13758@tuxdriver.com>
From: "John W. Linville" <linville@tuxdriver.com>
Date: Thu, 28 Aug 2014 14:17:14 -0400
> Please pull this batch of fixes intended for the 3.17 stream.
>
> For the Bluetooth/6LowPAN/802.15.4 bits, Johan says:
>
> 'It contains a connection reference counting fix for LE where a
> connection might stay up even though it should get disconnected.
>
> The other 802.15.4 6LoWPAN related patches were sent to the bluetooth
> tree by Alexander Aring and described as follows by him:
>
> "
> these patches contains patches for the bluetooth branch.
>
> This series includes memory leak fixes and an errno value fix.
> Also there are two patches for sending and receiving 1280 6LoWPAN
> packets, which makes the IEEE 802.15.4 6LoWPAN stack more RFC
> compliant.
> "'
>
> Along with that...
>
> Alexey Khoroshilov fixes a use-after-free bug on at76c50x-usb.
>
> Hauke Mehrtens adds a PCI ID to bcma.
>
> Himangi Saraogi fixes a silly "A || A" test in rtlwifi.
>
> Larry Finger adds a device ID to rtl8192cu.
>
> Maks Naumov fixes a strncmp argument in ath9k.
>
> Álvaro Fernández Rojas adds a PCI ID to ssb.
>
> Please let me know if there are problems!
Pulled, thanks a lot John.
^ permalink raw reply
* Re: [net-next PATCH] pktgen: add flag NO_TIMESTAMP to disable timestamping
From: David Miller @ 2014-09-02 1:07 UTC (permalink / raw)
To: brouer; +Cc: netdev, greearb, robert
In-Reply-To: <20140828161447.6652.59388.stgit@dragon>
From: Jesper Dangaard Brouer <brouer@redhat.com>
Date: Thu, 28 Aug 2014 18:14:47 +0200
> Then testing the TX limits of the stack, then it is useful to
> be-able to disable the do_gettimeofday() timetamping on every packet.
>
> This implements a pktgen flag NO_TIMESTAMP which will disable this
> call to do_gettimeofday().
>
> The performance change on (my system E5-2695) with skb_clone=0, goes
> from TX 2,423,751 pps to 2,567,165 pps with flag NO_TIMESTAMP. Thus,
> the cost of do_gettimeofday() or saving is approx 23 nanosec.
>
> Signed-off-by: Jesper Dangaard Brouer <brouer@redhat.com>
This is fine, applied, thanks!
^ permalink raw reply
* Re: [PATCH net-next 2/2] bnx2x: fix tunneled GSO over IPv6
From: David Miller @ 2014-09-02 0:54 UTC (permalink / raw)
To: Dmitry.Kravkov; +Cc: netdev, dan.carpenter
In-Reply-To: <1409234064-20619-2-git-send-email-Dmitry.Kravkov@qlogic.com>
From: Dmitry Kravkov <Dmitry.Kravkov@qlogic.com>
Date: Thu, 28 Aug 2014 16:54:24 +0300
> Set correct bit for packed description.
>
> Introduced in e42780b66aab88d3a82b6087bcd6095b90eecde7
> bnx2x: Utilize FW 7.10.51
>
> Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
> Signed-off-by: Dmitry Kravkov <Dmitry.Kravkov@qlogic.com>
Applied.
^ permalink raw reply
* Re: [PATCH net-next 1/2] bnx2x: prevent incorrect byte-swap in BE
From: David Miller @ 2014-09-02 0:54 UTC (permalink / raw)
To: Dmitry.Kravkov; +Cc: netdev, dan.carpenter
In-Reply-To: <1409234064-20619-1-git-send-email-Dmitry.Kravkov@qlogic.com>
From: Dmitry Kravkov <Dmitry.Kravkov@qlogic.com>
Date: Thu, 28 Aug 2014 16:54:23 +0300
> Fixes incorrectly defined struct in FW HSI for BE platform.
> Affects tunneling, tx-switching and anti-spoofing.
>
> Introduced in e42780b66aab88d3a82b6087bcd6095b90eecde7
> bnx2x: Utilize FW 7.10.51
>
> Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
> Signed-off-by: Dmitry Kravkov <Dmitry.Kravkov@qlogic.com>
Applied.
^ permalink raw reply
* Re: [PATCH v4 net-next 2/2] tipc: add name distributor resiliency queue
From: David Miller @ 2014-09-02 0:53 UTC (permalink / raw)
To: erik.hugne; +Cc: jon.maloy, ying.xue, richard.alpe, netdev, tipc-discussion
In-Reply-To: <1409209727-15265-2-git-send-email-erik.hugne@ericsson.com>
From: <erik.hugne@ericsson.com>
Date: Thu, 28 Aug 2014 09:08:47 +0200
> TIPC name table updates are distributed asynchronously in a cluster,
> entailing a risk of certain race conditions. E.g., if two nodes
> simultaneously issue conflicting (overlapping) publications, this may
> not be detected until both publications have reached a third node, in
> which case one of the publications will be silently dropped on that
> node. Hence, we end up with an inconsistent name table.
>
> In most cases this conflict is just a temporary race, e.g., one
> node is issuing a publication under the assumption that a previous,
> conflicting, publication has already been withdrawn by the other node.
> However, because of the (rtt related) distributed update delay, this
> may not yet hold true on all nodes. The symptom of this failure is a
> syslog message: "tipc: Cannot publish {%u,%u,%u}, overlap error".
>
> In this commit we add a resiliency queue at the receiving end of
> the name table distributor. When insertion of an arriving publication
> fails, we retain it in this queue for a short amount of time, assuming
> that another update will arrive very soon and clear the conflict. If so
> happens, we insert the publication, otherwise we drop it.
>
> The (configurable) retention value defaults to 2000 ms. Knowing from
> experience that the situation described above is extremely rare, there
> is no risk that the queue will accumulate any large number of items.
>
> Signed-off-by: Erik Hugne <erik.hugne@ericsson.com>
> Signed-off-by: Jon Maloy <jon.maloy@ericsson.com>
> Acked-by: Ying Xue <ying.xue@windriver.com>
...
> +static void tipc_named_add_backlog(struct distr_item *i, u32 type, u32 node)
> +{
> + struct distr_queue_item *e;
> + unsigned long now = get_jiffies_64();
> +
> + e = kzalloc(sizeof(*e), GFP_ATOMIC);
> + if (!e)
> + return;
I don't like this new (effectively silent) failure mode, but this isn't
my code so I don't care that much. Applied.
^ permalink raw reply
* Re: [PATCH v4 net-next 1/2] tipc: refactor name table updates out of named packet receive routine
From: David Miller @ 2014-09-02 0:52 UTC (permalink / raw)
To: erik.hugne; +Cc: jon.maloy, ying.xue, richard.alpe, netdev, tipc-discussion
In-Reply-To: <1409209727-15265-1-git-send-email-erik.hugne@ericsson.com>
From: <erik.hugne@ericsson.com>
Date: Thu, 28 Aug 2014 09:08:46 +0200
> From: Erik Hugne <erik.hugne@ericsson.com>
>
> We need to perform the same actions when processing deferred name
> table updates, so this functionality is moved to a separate
> function.
>
> Signed-off-by: Erik Hugne <erik.hugne@ericsson.com>
> Signed-off-by: Jon Maloy <jon.maloy@ericsson.com>
> Acked-by: Ying Xue <ying.xue@windriver.com>
Applied.
^ permalink raw reply
* Re: e1000: convert to build_skb/napi_gro_frags api
From: Jeff Kirsher @ 2014-09-02 0:30 UTC (permalink / raw)
To: Florian Westphal; +Cc: e1000-devel, netdev
In-Reply-To: <1409423307-23470-1-git-send-email-fw@strlen.de>
[-- Attachment #1.1: Type: text/plain, Size: 731 bytes --]
On Sat, 2014-08-30 at 20:28 +0200, Florian Westphal wrote:
> e1000 driver preallocates skbs, then sends them up the stack.
>
> This series changes the rx routine to only preallocate data buffers,
> then initialize skb right before passing it up the stack.
>
> This gives slight performance inprovements as the skb will be
> fresh in the cache once its allocated/initialized.
>
> The default-mtu 1500 path is converted to build_skb()/netdev_alloc_frag.
>
> Jumbo path is converted to napi_gro_frags.
>
> Note that this has only been tested with kvms e1000 emulation.
>
Can you re-spin the series with Sergei's suggest change for patch 7,
please? I will await your v2 before picking up this series, thanks!
[-- Attachment #1.2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 819 bytes --]
[-- Attachment #2: Type: text/plain, Size: 155 bytes --]
------------------------------------------------------------------------------
Slashdot TV.
Video for Nerds. Stuff that matters.
http://tv.slashdot.org/
[-- Attachment #3: Type: text/plain, Size: 257 bytes --]
_______________________________________________
E1000-devel mailing list
E1000-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/e1000-devel
To learn more about Intel® Ethernet, visit http://communities.intel.com/community/wired
^ permalink raw reply
* Re: [PATCH 1/2] ipv6: add sysctl_mld_qrv to configure query robustness variable
From: Flavio Leitner @ 2014-09-02 0:05 UTC (permalink / raw)
To: Hannes Frederic Sowa; +Cc: netdev
In-Reply-To: <aa72acbd19015e6db6b2d425fb6ebf6a8fa9c3b5.1409601046.git.hannes@stressinduktion.org>
Hi Hannes,
On Mon, Sep 01, 2014 at 09:55:34PM +0200, Hannes Frederic Sowa wrote:
> This patch adds a new sysctl_mld_qrv knob to configure the mldv1/v2 query
> robustness variable. It specifies how many retransmit of unsolicited mld
> retransmit should happen. Admins might want to tune this on lossy links.
>
> Also reset mld state on interface down/up, so we pick up new sysctl
> settings during interface up event.
>
> IPv6 certification requests this knob to be available.
>
> I didn't make this knob netns specific, as it is mostly a setting in a
> physical environment and should be per host.
>
> Cc: Flavio Leitner <fbl@redhat.com>
> Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
> ---
> v2) no changes to original version
>
> Documentation/networking/ip-sysctl.txt | 3 +++
> include/net/ipv6.h | 1 +
> net/ipv6/mcast.c | 20 ++++++++++++--------
> net/ipv6/sysctl_net_ipv6.c | 10 ++++++++++
> 4 files changed, 26 insertions(+), 8 deletions(-)
>
> diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
> index 3cce8ea..b7fe844 100644
> --- a/Documentation/networking/ip-sysctl.txt
> +++ b/Documentation/networking/ip-sysctl.txt
> @@ -1152,6 +1152,9 @@ anycast_src_echo_reply - BOOLEAN
> FALSE: disabled
> Default: FALSE
>
> +mld_qrv - INTEGER
> + Controls the MLD query robustness variable (see RFC3810 9.1).
> +
> IPv6 Fragmentation:
>
> ip6frag_high_thresh - INTEGER
> diff --git a/include/net/ipv6.h b/include/net/ipv6.h
> index a2db816..7e247e9 100644
> --- a/include/net/ipv6.h
> +++ b/include/net/ipv6.h
> @@ -121,6 +121,7 @@ struct frag_hdr {
>
> /* sysctls */
> extern int sysctl_mld_max_msf;
> +extern int sysctl_mld_qrv;
>
> #define _DEVINC(net, statname, modifier, idev, field) \
> ({ \
> diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
> index 7088179..6efb0e5 100644
> --- a/net/ipv6/mcast.c
> +++ b/net/ipv6/mcast.c
> @@ -121,6 +121,7 @@ static int ip6_mc_leave_src(struct sock *sk, struct ipv6_mc_socklist *iml,
> #define IPV6_MLD_MAX_MSF 64
>
> int sysctl_mld_max_msf __read_mostly = IPV6_MLD_MAX_MSF;
> +int sysctl_mld_qrv __read_mostly = MLD_QRV_DEFAULT;
>
> /*
> * socket join on multicast group
> @@ -1196,7 +1197,7 @@ static void mld_update_qrv(struct inet6_dev *idev,
> if (mlh2->mld2q_qrv > 0)
> idev->mc_qrv = mlh2->mld2q_qrv;
>
> - if (unlikely(idev->mc_qrv < 2)) {
> + if (unlikely(idev->mc_qrv < MLD_QRV_DEFAULT)) {
> net_warn_ratelimited("IPv6: MLD: clamping QRV from %u to %u!\n",
> idev->mc_qrv, MLD_QRV_DEFAULT);
> idev->mc_qrv = MLD_QRV_DEFAULT;
You allow the sysctl to be 1, but here it is limited to 2?
> @@ -2478,6 +2479,14 @@ void ipv6_mc_down(struct inet6_dev *idev)
> mld_clear_delrec(idev);
> }
>
> +static void ipv6_mc_reset(struct inet6_dev *idev)
> +{
> + idev->mc_qrv = sysctl_mld_qrv;
> + idev->mc_qi = MLD_QI_DEFAULT;
> + idev->mc_qri = MLD_QRI_DEFAULT;
> + idev->mc_v1_seen = 0;
> + idev->mc_maxdelay = unsolicited_report_interval(idev);
> +}
>
> /* Device going up */
>
> @@ -2488,6 +2497,7 @@ void ipv6_mc_up(struct inet6_dev *idev)
> /* Install multicast list, except for all-nodes (already installed) */
>
> read_lock_bh(&idev->lock);
> + ipv6_mc_reset(idev);
ok, up and down the interface to get the sysctl value applied.
> for (i = idev->mc_list; i; i = i->next)
> igmp6_group_added(i);
> read_unlock_bh(&idev->lock);
> @@ -2508,13 +2518,7 @@ void ipv6_mc_init_dev(struct inet6_dev *idev)
> (unsigned long)idev);
> setup_timer(&idev->mc_dad_timer, mld_dad_timer_expire,
> (unsigned long)idev);
> -
> - idev->mc_qrv = MLD_QRV_DEFAULT;
> - idev->mc_qi = MLD_QI_DEFAULT;
> - idev->mc_qri = MLD_QRI_DEFAULT;
> -
> - idev->mc_maxdelay = unsolicited_report_interval(idev);
> - idev->mc_v1_seen = 0;
> + ipv6_mc_reset(idev);
looks good to me.
> write_unlock_bh(&idev->lock);
> }
>
> diff --git a/net/ipv6/sysctl_net_ipv6.c b/net/ipv6/sysctl_net_ipv6.c
> index 0c56c93..c5c10fa 100644
> --- a/net/ipv6/sysctl_net_ipv6.c
> +++ b/net/ipv6/sysctl_net_ipv6.c
> @@ -16,6 +16,8 @@
> #include <net/addrconf.h>
> #include <net/inet_frag.h>
>
> +static int one = 1;
> +
Although that can be reused later for other purposes, it's nice to
have a comment telling where that value came from. Since you have
defined MLD_QRV_DEFAULT, it helps. Still I didn't know about
rfc6636#section-4.5, so I'd appreciate if you include that info
either in ip-sysctl.txt or close to MLD_QRV_DEFAULT.
E.g.:
/* See RFC3810 9.1 and rfc6636 4.5 */
+int sysctl_mld_qrv __read_mostly = MLD_QRV_DEFAULT;
Actually, maybe that int could be something not specific to ipv6
because I believe there are more users of the same thing. That's ok,
just a comment and it's not part of this patch.
> static struct ctl_table ipv6_table_template[] = {
> {
> .procname = "bindv6only",
> @@ -63,6 +65,14 @@ static struct ctl_table ipv6_rotable[] = {
> .mode = 0644,
> .proc_handler = proc_dointvec
> },
> + {
> + .procname = "mld_qrv",
> + .data = &sysctl_mld_qrv,
> + .maxlen = sizeof(int),
> + .mode = 0644,
> + .proc_handler = proc_dointvec_minmax,
> + .extra1 = &one
> + },
> { }
> };
>
> --
> 1.9.3
>
^ permalink raw reply
* Re: [PATCH v2] net: sh_eth: fix driver dependencies
From: Simon Horman @ 2014-09-01 23:39 UTC (permalink / raw)
To: Geert Uytterhoeven
Cc: Bartlomiej Zolnierkiewicz, David S. Miller, Magnus Damm,
Kyungmin Park, netdev@vger.kernel.org, Linux-sh list,
linux-kernel@vger.kernel.org
In-Reply-To: <CAMuHMdWGdD+-o9Z8gPYwJWJmjhBqfw0HA4ve=RH+adLFJEZa8Q@mail.gmail.com>
On Mon, Sep 01, 2014 at 06:36:19PM +0200, Geert Uytterhoeven wrote:
> On Mon, Sep 1, 2014 at 4:25 PM, Bartlomiej Zolnierkiewicz
> <b.zolnierkie@samsung.com> wrote:
> > Renesas SuperH Ethernet support should be available only on
> > Renesas ARM SoCs and SuperH architecture.
> >
> > Signed-off-by: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
> > Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
> > Cc: Simon Horman <horms@verge.net.au>
> > Cc: Magnus Damm <magnus.damm@gmail.com>
> > ---
> > v2:
> > - s/ARCH_SH/SUPERH/ (thanks to Sergei Shtylyov)
>
> Acked-by: Geert Uytterhoeven <geert+renesas@glider.be>
Acked-by: Simon Horman <horms+renesas@verge.net.au>
^ permalink raw reply
* Re: [PATCH 0/2] Get rid of ndo_xmit_flush
From: David Miller @ 2014-09-01 22:35 UTC (permalink / raw)
To: hannes
Cc: netdev, therbert, jhs, edumazet, jeffrey.t.kirsher, rusty,
dborkman, brouer, john.r.fastabend
In-Reply-To: <1409610669.21965.55.camel@localhost>
From: Hannes Frederic Sowa <hannes@stressinduktion.org>
Date: Tue, 02 Sep 2014 00:31:09 +0200
> I am afraid that TX-lock is per nic-queue and it won't work out that
> easy because skbs for different queues can reside in a Qdisc.
Batching will help mostly when netif_queue_start() triggers, when we
are in steady state stopping and re-starting the txq.
What we really care about are the qdisc <--> txq one to one
relationship which is by far the most common case.
In the multiple txq to qdisc case, we still can benefit because
packets for one txq will still tend to bunch op and give deferral
opportunities.
^ permalink raw reply
* [PATCH] ethernet: nvidia: Remove extra parens
From: David Wood @ 2014-09-01 22:31 UTC (permalink / raw)
To: netdev
Cc: David S. Miller, Alexander Gordeev, Eric W. Biederman,
Antonio Ospite, Paul Gortmaker, Jiri Pirko, Jeff Kirsher,
Wilfried Klaebe, Ivan Vecera, linux-kernel, trivial
Remove unnecessary double parenthesis around if statement.
Signed-off-by: David Wood <devel@dtwood.uk>
---
drivers/net/ethernet/nvidia/forcedeth.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/nvidia/forcedeth.c b/drivers/net/ethernet/nvidia/forcedeth.c
index 925b296..f39cae6 100644
--- a/drivers/net/ethernet/nvidia/forcedeth.c
+++ b/drivers/net/ethernet/nvidia/forcedeth.c
@@ -1481,7 +1481,7 @@ static int phy_init(struct net_device *dev)
}
/* phy vendor specific configuration */
- if ((np->phy_oui == PHY_OUI_CICADA)) {
+ if (np->phy_oui == PHY_OUI_CICADA) {
if (init_cicada(dev, np, phyinterface)) {
netdev_info(dev, "%s: phy init failed\n",
pci_name(np->pci_dev));
--
2.0.3
^ permalink raw reply related
* Re: [PATCH 0/2] Get rid of ndo_xmit_flush
From: Hannes Frederic Sowa @ 2014-09-01 22:31 UTC (permalink / raw)
To: David Miller
Cc: netdev, therbert, jhs, edumazet, jeffrey.t.kirsher, rusty,
dborkman, brouer, john.r.fastabend
In-Reply-To: <20140901.145646.174847768842584425.davem@davemloft.net>
On Mo, 2014-09-01 at 14:56 -0700, David Miller wrote:
> From: Hannes Frederic Sowa <hannes@stressinduktion.org>
> Date: Mon, 01 Sep 2014 22:05:42 +0200
>
> > But as soon as we try to make Qdiscs absolutely lockless, we don't have
> > any guard that we don't concurrently dequeue skbs from it and suddenly
> > one Qdisc dequeue processing entity couldn't notify the driver that the
> > end of the batching was reached. I think this could become a problem
> > depending on how much of the locking is removed?
>
> I am certain that batching will require taking the device transmit
> lock over the ->ndo_start_xmit() invocations, and therefore the
> deferral decisions must atomically be made inside of that context.
I'll stop to throw doubt into this discussion now. ;)
I am afraid that TX-lock is per nic-queue and it won't work out that
easy because skbs for different queues can reside in a Qdisc.
Bye,
Hannes
^ permalink raw reply
* Re: [PATCH] ipv6: fix rtnl locking in setsockopt for anycast and multicast
From: Hannes Frederic Sowa @ 2014-09-01 22:26 UTC (permalink / raw)
To: Sabrina Dubroca
Cc: Cong Wang, Tommi Rantala, David S. Miller, Alexey Kuznetsov,
James Morris, Hideaki YOSHIFUJI, Patrick McHardy, netdev, LKML,
trinity, Dave Jones
In-Reply-To: <20140901210520.GB25543@kria>
Hi,
On Mo, 2014-09-01 at 23:05 +0200, Sabrina Dubroca wrote:
> Calling setsockopt with IPV6_JOIN_ANYCAST or IPV6_LEAVE_ANYCAST
> triggers the assertion in addrconf_join_solict()/addrconf_leave_solict()
>
> ipv6_sock_ac_join(), ipv6_sock_ac_drop(), ipv6_sock_ac_close() need to
> take RTNL before calling ipv6_dev_ac_inc/dec. Same thing with
> ipv6_sock_mc_join(), ipv6_sock_mc_drop(), ipv6_sock_mc_close() before
> calling ipv6_dev_mc_inc/dec.
>
> This patch moves ASSERT_RTNL() up a level in the call stack.
>
> Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
> Signed-off-by: Sabrina Dubroca <sd@queasysnail.net>
> Reported-by: Tommi Rantala <tt.rantala@gmail.com>
> ---
> I included Cong's Signed-off-by for the first part of the patch,
> I hope that's OK.
>
> This patch is based on -next, but since the assertion can also be
> triggered on a current kernel (tested on a 3.16), I think it should
> also go in stable.
Ack, thus you should base the patch on the net tree.
>
> include/linux/netdevice.h | 4 ++--
> net/core/dev.c | 11 ++++++-----
> net/ipv6/addrconf.c | 15 +++++----------
> net/ipv6/anycast.c | 30 +++++++++++++++++++-----------
> net/ipv6/mcast.c | 16 ++++++++++++++++
> 5 files changed, 48 insertions(+), 28 deletions(-)
>
> diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
> index 429801370d0c..1ae0e745b1b1 100644
> --- a/include/linux/netdevice.h
> +++ b/include/linux/netdevice.h
> @@ -2077,8 +2077,8 @@ void __dev_remove_pack(struct packet_type *pt);
> void dev_add_offload(struct packet_offload *po);
> void dev_remove_offload(struct packet_offload *po);
>
> -struct net_device *dev_get_by_flags_rcu(struct net *net, unsigned short flags,
> - unsigned short mask);
> +struct net_device *dev_get_by_flags(struct net *net, unsigned short flags,
> + unsigned short mask);
> struct net_device *dev_get_by_name(struct net *net, const char *name);
> struct net_device *dev_get_by_name_rcu(struct net *net, const char *name);
> struct net_device *__dev_get_by_name(struct net *net, const char *name);
> diff --git a/net/core/dev.c b/net/core/dev.c
> index 443b814db05b..8fede6ef4a39 100644
> --- a/net/core/dev.c
> +++ b/net/core/dev.c
> @@ -897,23 +897,24 @@ struct net_device *dev_getfirstbyhwtype(struct net *net, unsigned short type)
> EXPORT_SYMBOL(dev_getfirstbyhwtype);
>
> /**
> - * dev_get_by_flags_rcu - find any device with given flags
> + * dev_get_by_flags - find any device with given flags
> * @net: the applicable net namespace
> * @if_flags: IFF_* values
> * @mask: bitmask of bits in if_flags to check
> *
> * Search for any interface with the given flags. Returns NULL if a device
> * is not found or a pointer to the device. Must be called inside
> - * rcu_read_lock(), and result refcount is unchanged.
> + * rtnl_lock(), and result refcount is unchanged.
> */
>
> -struct net_device *dev_get_by_flags_rcu(struct net *net, unsigned short if_flags,
> +struct net_device *dev_get_by_flags(struct net *net, unsigned short if_flags,
> unsigned short mask)
> {
> struct net_device *dev, *ret;
>
> + ASSERT_RTNL();
> ret = NULL;
> - for_each_netdev_rcu(net, dev) {
> + for_each_netdev(net, dev) {
> if (((dev->flags ^ if_flags) & mask) == 0) {
> ret = dev;
> break;
> @@ -921,7 +922,7 @@ struct net_device *dev_get_by_flags_rcu(struct net *net, unsigned short if_flags
> }
> return ret;
> }
> -EXPORT_SYMBOL(dev_get_by_flags_rcu);
> +EXPORT_SYMBOL(dev_get_by_flags);
I don't have a very strong opinion on that, but think we shouldn't touch
this function. In general it looks like a useful one and if you force
rtnl lock on it you cannot call it from bh anymore. I think we should
keep rcu locking here and in the anycast code. It shouldn't matter much.
> /**
> * dev_valid_name - check if name is okay for network device
> diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
> index 267ce3caee24..7ada65937d23 100644
> --- a/net/ipv6/addrconf.c
> +++ b/net/ipv6/addrconf.c
> @@ -1690,14 +1690,12 @@ void addrconf_dad_failure(struct inet6_ifaddr *ifp)
> addrconf_mod_dad_work(ifp, 0);
> }
>
> -/* Join to solicited addr multicast group. */
> -
> +/* Join to solicited addr multicast group.
> + * caller must hold RTNL */
> void addrconf_join_solict(struct net_device *dev, const struct in6_addr *addr)
> {
> struct in6_addr maddr;
>
> - ASSERT_RTNL();
> -
> if (dev->flags&(IFF_LOOPBACK|IFF_NOARP))
> return;
>
> @@ -1705,12 +1703,11 @@ void addrconf_join_solict(struct net_device *dev, const struct in6_addr *addr)
> ipv6_dev_mc_inc(dev, &maddr);
> }
>
> +/* caller must hold RTNL */
> void addrconf_leave_solict(struct inet6_dev *idev, const struct in6_addr *addr)
> {
> struct in6_addr maddr;
>
> - ASSERT_RTNL();
> -
> if (idev->dev->flags&(IFF_LOOPBACK|IFF_NOARP))
> return;
>
> @@ -1718,12 +1715,11 @@ void addrconf_leave_solict(struct inet6_dev *idev, const struct in6_addr *addr)
> __ipv6_dev_mc_dec(idev, &maddr);
> }
>
> +/* caller must hold RTNL */
> static void addrconf_join_anycast(struct inet6_ifaddr *ifp)
> {
> struct in6_addr addr;
>
> - ASSERT_RTNL();
> -
> if (ifp->prefix_len >= 127) /* RFC 6164 */
> return;
> ipv6_addr_prefix(&addr, &ifp->addr, ifp->prefix_len);
> @@ -1732,12 +1728,11 @@ static void addrconf_join_anycast(struct inet6_ifaddr *ifp)
> ipv6_dev_ac_inc(ifp->idev->dev, &addr);
> }
>
> +/* caller must hold RTNL */
> static void addrconf_leave_anycast(struct inet6_ifaddr *ifp)
> {
> struct in6_addr addr;
>
> - ASSERT_RTNL();
> -
> if (ifp->prefix_len >= 127) /* RFC 6164 */
> return;
> ipv6_addr_prefix(&addr, &ifp->addr, ifp->prefix_len);
> diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c
> index 210183244689..572c2faede55 100644
> --- a/net/ipv6/anycast.c
> +++ b/net/ipv6/anycast.c
> @@ -77,7 +77,7 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
> pac->acl_next = NULL;
> pac->acl_addr = *addr;
>
> - rcu_read_lock();
> + rtnl_lock();
We would need to keep rcu_read_lock inside rtnl_lock if you decide to
keep dev_get_by_flags_rcu around.
> if (ifindex == 0) {
> struct rt6_info *rt;
>
> @@ -90,11 +90,11 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
> goto error;
> } else {
> /* router, no matching interface: just pick one */
> - dev = dev_get_by_flags_rcu(net, IFF_UP,
> - IFF_UP | IFF_LOOPBACK);
> + dev = dev_get_by_flags(net, IFF_UP,
> + IFF_UP | IFF_LOOPBACK);
> }
> } else
> - dev = dev_get_by_index_rcu(net, ifindex);
> + dev = __dev_get_by_index(net, ifindex);
>
> if (dev == NULL) {
> err = -ENODEV;
> @@ -136,7 +136,7 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
> }
>
> error:
> - rcu_read_unlock();
> + rtnl_unlock();
...here, too.
> if (pac)
> sock_kfree_s(sk, pac, sizeof(*pac));
> return err;
> @@ -171,13 +171,15 @@ int ipv6_sock_ac_drop(struct sock *sk, int ifindex, const struct in6_addr *addr)
>
> spin_unlock_bh(&ipv6_sk_ac_lock);
>
> - rcu_read_lock();
> - dev = dev_get_by_index_rcu(net, pac->acl_ifindex);
> + rtnl_lock();
> + dev = __dev_get_by_index(net, pac->acl_ifindex);
> if (dev)
> ipv6_dev_ac_dec(dev, &pac->acl_addr);
> - rcu_read_unlock();
> + rtnl_unlock();
>
> sock_kfree_s(sk, pac, sizeof(*pac));
> + if (!dev)
> + return -ENODEV;
> return 0;
> }
>
> @@ -198,12 +200,12 @@ void ipv6_sock_ac_close(struct sock *sk)
> spin_unlock_bh(&ipv6_sk_ac_lock);
>
> prev_index = 0;
> - rcu_read_lock();
> + rtnl_lock();
> while (pac) {
> struct ipv6_ac_socklist *next = pac->acl_next;
>
> if (pac->acl_ifindex != prev_index) {
> - dev = dev_get_by_index_rcu(net, pac->acl_ifindex);
> + dev = __dev_get_by_index(net, pac->acl_ifindex);
> prev_index = pac->acl_ifindex;
> }
> if (dev)
> @@ -211,7 +213,7 @@ void ipv6_sock_ac_close(struct sock *sk)
> sock_kfree_s(sk, pac, sizeof(*pac));
> pac = next;
> }
> - rcu_read_unlock();
> + rtnl_unlock();
> }
>
> static void aca_put(struct ifacaddr6 *ac)
> @@ -233,6 +235,8 @@ int ipv6_dev_ac_inc(struct net_device *dev, const struct in6_addr *addr)
> struct rt6_info *rt;
> int err;
>
> + ASSERT_RTNL();
> +
> idev = in6_dev_get(dev);
>
> if (idev == NULL)
> @@ -302,6 +306,8 @@ int __ipv6_dev_ac_dec(struct inet6_dev *idev, const struct in6_addr *addr)
> {
> struct ifacaddr6 *aca, *prev_aca;
>
> + ASSERT_RTNL();
> +
> write_lock_bh(&idev->lock);
> prev_aca = NULL;
> for (aca = idev->ac_list; aca; aca = aca->aca_next) {
> @@ -336,6 +342,8 @@ static int ipv6_dev_ac_dec(struct net_device *dev, const struct in6_addr *addr)
> {
> struct inet6_dev *idev = __in6_dev_get(dev);
>
> + ASSERT_RTNL();
> +
> if (idev == NULL)
> return -ENODEV;
> return __ipv6_dev_ac_dec(idev, addr);
> diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
> index 70881795da96..d73ac1ef65f2 100644
> --- a/net/ipv6/mcast.c
> +++ b/net/ipv6/mcast.c
> @@ -172,6 +172,7 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
> mc_lst->next = NULL;
> mc_lst->addr = *addr;
>
> + rtnl_lock();
> rcu_read_lock();
> if (ifindex == 0) {
> struct rt6_info *rt;
> @@ -185,6 +186,7 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
>
> if (dev == NULL) {
> rcu_read_unlock();
> + rtnl_unlock();
> sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
> return -ENODEV;
> }
> @@ -202,6 +204,7 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
>
> if (err) {
> rcu_read_unlock();
> + rtnl_unlock();
> sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
> return err;
> }
> @@ -212,6 +215,7 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
> spin_unlock(&ipv6_sk_mc_lock);
>
> rcu_read_unlock();
> + rtnl_unlock();
>
> return 0;
> }
> @@ -229,6 +233,7 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, const struct in6_addr *addr)
> if (!ipv6_addr_is_multicast(addr))
> return -EINVAL;
>
> + rtnl_lock();
> spin_lock(&ipv6_sk_mc_lock);
> for (lnk = &np->ipv6_mc_list;
> (mc_lst = rcu_dereference_protected(*lnk,
> @@ -252,12 +257,15 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, const struct in6_addr *addr)
> } else
> (void) ip6_mc_leave_src(sk, mc_lst, NULL);
> rcu_read_unlock();
> + rtnl_unlock();
> +
> atomic_sub(sizeof(*mc_lst), &sk->sk_omem_alloc);
> kfree_rcu(mc_lst, rcu);
> return 0;
> }
> }
> spin_unlock(&ipv6_sk_mc_lock);
> + rtnl_unlock();
>
> return -EADDRNOTAVAIL;
> }
> @@ -302,6 +310,7 @@ void ipv6_sock_mc_close(struct sock *sk)
> if (!rcu_access_pointer(np->ipv6_mc_list))
> return;
>
> + rtnl_lock();
> spin_lock(&ipv6_sk_mc_lock);
> while ((mc_lst = rcu_dereference_protected(np->ipv6_mc_list,
> lockdep_is_held(&ipv6_sk_mc_lock))) != NULL) {
> @@ -328,6 +337,7 @@ void ipv6_sock_mc_close(struct sock *sk)
> spin_lock(&ipv6_sk_mc_lock);
> }
> spin_unlock(&ipv6_sk_mc_lock);
> + rtnl_unlock();
> }
>
> int ip6_mc_source(int add, int omode, struct sock *sk,
> @@ -845,6 +855,8 @@ int ipv6_dev_mc_inc(struct net_device *dev, const struct in6_addr *addr)
> struct ifmcaddr6 *mc;
> struct inet6_dev *idev;
>
> + ASSERT_RTNL();
> +
> /* we need to take a reference on idev */
> idev = in6_dev_get(dev);
>
> @@ -916,6 +928,8 @@ int __ipv6_dev_mc_dec(struct inet6_dev *idev, const struct in6_addr *addr)
> {
> struct ifmcaddr6 *ma, **map;
>
> + ASSERT_RTNL();
> +
> write_lock_bh(&idev->lock);
> for (map = &idev->mc_list; (ma = *map) != NULL; map = &ma->next) {
> if (ipv6_addr_equal(&ma->mca_addr, addr)) {
> @@ -942,6 +956,8 @@ int ipv6_dev_mc_dec(struct net_device *dev, const struct in6_addr *addr)
> struct inet6_dev *idev;
> int err;
>
> + ASSERT_RTNL();
> +
Minor nit:
This one is not necessary and will be guarded by the __ipv6_dev_mc_dec
one.
> rcu_read_lock();
>
> idev = __in6_dev_get(dev);
Rest looks good to me, thanks,
Hannes
^ permalink raw reply
* [PATCH 9/9] net: xmit_list() becomes dev_hard_start_xmit().
From: David Miller @ 2014-09-01 22:25 UTC (permalink / raw)
To: netdev
Now fundamentally we can process lists of SKBs as cheaply
as single packets.
Signed-off-by: David S. Miller <davem@davemloft.net>
---
net/core/dev.c | 15 ++-------------
1 file changed, 2 insertions(+), 13 deletions(-)
diff --git a/net/core/dev.c b/net/core/dev.c
index c89da4f..6857d57 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2570,8 +2570,8 @@ static int xmit_one(struct sk_buff *skb, struct net_device *dev,
return rc;
}
-static struct sk_buff *xmit_list(struct sk_buff *first, struct net_device *dev,
- struct netdev_queue *txq, int *ret)
+struct sk_buff *dev_hard_start_xmit(struct sk_buff *first, struct net_device *dev,
+ struct netdev_queue *txq, int *ret)
{
struct sk_buff *skb = first;
int rc = NETDEV_TX_OK;
@@ -2673,17 +2673,6 @@ out_null:
return NULL;
}
-struct sk_buff *dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
- struct netdev_queue *txq, int *ret)
-{
- if (likely(!skb->next)) {
- *ret = xmit_one(skb, dev, txq, false);
- return skb;
- }
-
- return xmit_list(skb, dev, txq, ret);
-}
-
static void qdisc_pkt_len_init(struct sk_buff *skb)
{
const struct skb_shared_info *shinfo = skb_shinfo(skb);
--
1.7.11.7
^ permalink raw reply related
* [PATCH 8/9] net: Don't keep around original SKB when we software segment GSO frames.
From: David Miller @ 2014-09-01 22:25 UTC (permalink / raw)
To: netdev
Just maintain the list properly by returning the head of the remaining
SKB list from dev_hard_start_xmit().
Signed-off-by: David S. Miller <davem@davemloft.net>
---
include/linux/netdevice.h | 4 +--
net/core/dev.c | 79 +++++++++--------------------------------------
net/sched/sch_generic.c | 2 +-
3 files changed, 17 insertions(+), 68 deletions(-)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 47c49ba..202c25a 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -2828,8 +2828,8 @@ int dev_change_carrier(struct net_device *, bool new_carrier);
int dev_get_phys_port_id(struct net_device *dev,
struct netdev_phys_port_id *ppid);
struct sk_buff *validate_xmit_skb(struct sk_buff *skb, struct net_device *dev);
-int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
- struct netdev_queue *txq);
+struct sk_buff *dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
+ struct netdev_queue *txq, int *ret);
int __dev_forward_skb(struct net_device *dev, struct sk_buff *skb);
int dev_forward_skb(struct net_device *dev, struct sk_buff *skb);
bool is_skb_forwardable(struct net_device *dev, struct sk_buff *skb);
diff --git a/net/core/dev.c b/net/core/dev.c
index 75bc5b0..c89da4f 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2485,52 +2485,6 @@ static int illegal_highdma(struct net_device *dev, struct sk_buff *skb)
return 0;
}
-struct dev_gso_cb {
- void (*destructor)(struct sk_buff *skb);
-};
-
-#define DEV_GSO_CB(skb) ((struct dev_gso_cb *)(skb)->cb)
-
-static void dev_gso_skb_destructor(struct sk_buff *skb)
-{
- struct dev_gso_cb *cb;
-
- kfree_skb_list(skb->next);
- skb->next = NULL;
-
- cb = DEV_GSO_CB(skb);
- if (cb->destructor)
- cb->destructor(skb);
-}
-
-/**
- * dev_gso_segment - Perform emulated hardware segmentation on skb.
- * @skb: buffer to segment
- * @features: device features as applicable to this skb
- *
- * This function segments the given skb and stores the list of segments
- * in skb->next.
- */
-static int dev_gso_segment(struct sk_buff *skb, netdev_features_t features)
-{
- struct sk_buff *segs;
-
- segs = skb_gso_segment(skb, features);
-
- /* Verifying header integrity only. */
- if (!segs)
- return 0;
-
- if (IS_ERR(segs))
- return PTR_ERR(segs);
-
- skb->next = segs;
- DEV_GSO_CB(skb)->destructor = skb->destructor;
- skb->destructor = dev_gso_skb_destructor;
-
- return 0;
-}
-
/* If MPLS offload request, verify we are testing hardware MPLS features
* instead of standard features for the netdev.
*/
@@ -2682,8 +2636,13 @@ struct sk_buff *validate_xmit_skb(struct sk_buff *skb, struct net_device *dev)
features &= dev->hw_enc_features;
if (netif_needs_gso(skb, features)) {
- if (unlikely(dev_gso_segment(skb, features)))
- goto out_kfree_skb;
+ struct sk_buff *segs;
+
+ segs = skb_gso_segment(skb, features);
+ kfree_skb(skb);
+ if (IS_ERR(segs))
+ segs = NULL;
+ skb = segs;
} else {
if (skb_needs_linearize(skb, features) &&
__skb_linearize(skb))
@@ -2714,26 +2673,16 @@ out_null:
return NULL;
}
-int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
- struct netdev_queue *txq)
+struct sk_buff *dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
+ struct netdev_queue *txq, int *ret)
{
- int rc = NETDEV_TX_OK;
-
- if (likely(!skb->next))
- return xmit_one(skb, dev, txq, false);
-
- skb->next = xmit_list(skb->next, dev, txq, &rc);
- if (likely(skb->next == NULL)) {
- skb->destructor = DEV_GSO_CB(skb)->destructor;
- consume_skb(skb);
- return rc;
+ if (likely(!skb->next)) {
+ *ret = xmit_one(skb, dev, txq, false);
+ return skb;
}
- kfree_skb(skb);
-
- return rc;
+ return xmit_list(skb, dev, txq, ret);
}
-EXPORT_SYMBOL_GPL(dev_hard_start_xmit);
static void qdisc_pkt_len_init(struct sk_buff *skb)
{
@@ -2945,7 +2894,7 @@ static int __dev_queue_xmit(struct sk_buff *skb, void *accel_priv)
if (!netif_xmit_stopped(txq)) {
__this_cpu_inc(xmit_recursion);
- rc = dev_hard_start_xmit(skb, dev, txq);
+ skb = dev_hard_start_xmit(skb, dev, txq, &rc);
__this_cpu_dec(xmit_recursion);
if (dev_xmit_complete(rc)) {
HARD_TX_UNLOCK(dev, txq);
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index f178798..a8bf9f9 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -129,7 +129,7 @@ int sch_direct_xmit(struct sk_buff *skb, struct Qdisc *q,
HARD_TX_LOCK(dev, txq, smp_processor_id());
if (!netif_xmit_frozen_or_stopped(txq))
- ret = dev_hard_start_xmit(skb, dev, txq);
+ skb = dev_hard_start_xmit(skb, dev, txq, &ret);
HARD_TX_UNLOCK(dev, txq);
--
1.7.11.7
^ permalink raw reply related
* [PATCH 7/9] net: Validate xmit SKBs right when we pull them out of the qdisc.
From: David Miller @ 2014-09-01 22:25 UTC (permalink / raw)
To: netdev
Signed-off-by: David S. Miller <davem@davemloft.net>
---
include/linux/netdevice.h | 1 +
net/core/dev.c | 6 +-----
net/sched/sch_generic.c | 5 ++++-
3 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 5050218..47c49ba 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -2827,6 +2827,7 @@ int dev_set_mac_address(struct net_device *, struct sockaddr *);
int dev_change_carrier(struct net_device *, bool new_carrier);
int dev_get_phys_port_id(struct net_device *dev,
struct netdev_phys_port_id *ppid);
+struct sk_buff *validate_xmit_skb(struct sk_buff *skb, struct net_device *dev);
int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
struct netdev_queue *txq);
int __dev_forward_skb(struct net_device *dev, struct sk_buff *skb);
diff --git a/net/core/dev.c b/net/core/dev.c
index 704a543..75bc5b0 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2656,7 +2656,7 @@ struct sk_buff *validate_xmit_vlan(struct sk_buff *skb, netdev_features_t featur
return skb;
}
-static struct sk_buff *validate_xmit_skb(struct sk_buff *skb, struct net_device *dev)
+struct sk_buff *validate_xmit_skb(struct sk_buff *skb, struct net_device *dev)
{
netdev_features_t features;
@@ -2719,10 +2719,6 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
{
int rc = NETDEV_TX_OK;
- skb = validate_xmit_skb(skb, dev);
- if (!skb)
- return rc;
-
if (likely(!skb->next))
return xmit_one(skb, dev, txq, false);
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index 05b3f5d..f178798 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -70,8 +70,11 @@ static inline struct sk_buff *dequeue_skb(struct Qdisc *q)
} else
skb = NULL;
} else {
- if (!(q->flags & TCQ_F_ONETXQUEUE) || !netif_xmit_frozen_or_stopped(txq))
+ if (!(q->flags & TCQ_F_ONETXQUEUE) || !netif_xmit_frozen_or_stopped(txq)) {
skb = q->dequeue(q);
+ if (skb)
+ skb = validate_xmit_skb(skb, qdisc_dev(q));
+ }
}
return skb;
--
1.7.11.7
^ permalink raw reply related
* [PATCH 6/9] net: Separate out SKB validation logic from transmit path.
From: David Miller @ 2014-09-01 22:25 UTC (permalink / raw)
To: netdev
dev_hard_start_xmit() does two things, it first validates and
canonicalizes the SKB, then it actually sends it.
Make a set of helper functions for doing the first part.
Signed-off-by: David S. Miller <davem@davemloft.net>
---
net/core/dev.c | 125 ++++++++++++++++++++++++++++++++-------------------------
1 file changed, 71 insertions(+), 54 deletions(-)
diff --git a/net/core/dev.c b/net/core/dev.c
index 6d82194..704a543 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2644,80 +2644,97 @@ out:
return skb;
}
-int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
- struct netdev_queue *txq)
+struct sk_buff *validate_xmit_vlan(struct sk_buff *skb, netdev_features_t features)
{
- int rc = NETDEV_TX_OK;
+ if (vlan_tx_tag_present(skb) &&
+ !vlan_hw_offload_capable(features, skb->vlan_proto)) {
+ skb = __vlan_put_tag(skb, skb->vlan_proto,
+ vlan_tx_tag_get(skb));
+ if (skb)
+ skb->vlan_tci = 0;
+ }
+ return skb;
+}
- if (likely(!skb->next)) {
- netdev_features_t features;
+static struct sk_buff *validate_xmit_skb(struct sk_buff *skb, struct net_device *dev)
+{
+ netdev_features_t features;
- /*
- * If device doesn't need skb->dst, release it right now while
- * its hot in this cpu cache
- */
- if (dev->priv_flags & IFF_XMIT_DST_RELEASE)
- skb_dst_drop(skb);
+ if (skb->next)
+ return skb;
- features = netif_skb_features(skb);
+ /* If device doesn't need skb->dst, release it right now while
+ * its hot in this cpu cache
+ */
+ if (dev->priv_flags & IFF_XMIT_DST_RELEASE)
+ skb_dst_drop(skb);
- if (vlan_tx_tag_present(skb) &&
- !vlan_hw_offload_capable(features, skb->vlan_proto)) {
- skb = __vlan_put_tag(skb, skb->vlan_proto,
- vlan_tx_tag_get(skb));
- if (unlikely(!skb))
- goto out;
+ features = netif_skb_features(skb);
+ skb = validate_xmit_vlan(skb, features);
+ if (unlikely(!skb))
+ goto out_null;
- skb->vlan_tci = 0;
- }
+ /* If encapsulation offload request, verify we are testing
+ * hardware encapsulation features instead of standard
+ * features for the netdev
+ */
+ if (skb->encapsulation)
+ features &= dev->hw_enc_features;
- /* If encapsulation offload request, verify we are testing
- * hardware encapsulation features instead of standard
- * features for the netdev
- */
- if (skb->encapsulation)
- features &= dev->hw_enc_features;
+ if (netif_needs_gso(skb, features)) {
+ if (unlikely(dev_gso_segment(skb, features)))
+ goto out_kfree_skb;
+ } else {
+ if (skb_needs_linearize(skb, features) &&
+ __skb_linearize(skb))
+ goto out_kfree_skb;
- if (netif_needs_gso(skb, features)) {
- if (unlikely(dev_gso_segment(skb, features)))
- goto out_kfree_skb;
- if (skb->next)
- goto gso;
- } else {
- if (skb_needs_linearize(skb, features) &&
- __skb_linearize(skb))
+ /* If packet is not checksummed and device does not
+ * support checksumming for this protocol, complete
+ * checksumming here.
+ */
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ if (skb->encapsulation)
+ skb_set_inner_transport_header(skb,
+ skb_checksum_start_offset(skb));
+ else
+ skb_set_transport_header(skb,
+ skb_checksum_start_offset(skb));
+ if (!(features & NETIF_F_ALL_CSUM) &&
+ skb_checksum_help(skb))
goto out_kfree_skb;
-
- /* If packet is not checksummed and device does not
- * support checksumming for this protocol, complete
- * checksumming here.
- */
- if (skb->ip_summed == CHECKSUM_PARTIAL) {
- if (skb->encapsulation)
- skb_set_inner_transport_header(skb,
- skb_checksum_start_offset(skb));
- else
- skb_set_transport_header(skb,
- skb_checksum_start_offset(skb));
- if (!(features & NETIF_F_ALL_CSUM) &&
- skb_checksum_help(skb))
- goto out_kfree_skb;
- }
}
+ }
+
+ return skb;
+
+out_kfree_skb:
+ kfree_skb(skb);
+out_null:
+ return NULL;
+}
+
+int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
+ struct netdev_queue *txq)
+{
+ int rc = NETDEV_TX_OK;
+
+ skb = validate_xmit_skb(skb, dev);
+ if (!skb)
+ return rc;
+ if (likely(!skb->next))
return xmit_one(skb, dev, txq, false);
- }
-gso:
skb->next = xmit_list(skb->next, dev, txq, &rc);
if (likely(skb->next == NULL)) {
skb->destructor = DEV_GSO_CB(skb)->destructor;
consume_skb(skb);
return rc;
}
-out_kfree_skb:
+
kfree_skb(skb);
-out:
+
return rc;
}
EXPORT_SYMBOL_GPL(dev_hard_start_xmit);
--
1.7.11.7
^ permalink raw reply related
* [PATCH 5/9] net: Have xmit_list() signal more==true when appropriate.
From: David Miller @ 2014-09-01 22:24 UTC (permalink / raw)
To: netdev
Signed-off-by: David S. Miller <davem@davemloft.net>
---
net/core/dev.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/net/core/dev.c b/net/core/dev.c
index f0ed5a6..6d82194 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2600,7 +2600,7 @@ netdev_features_t netif_skb_features(struct sk_buff *skb)
EXPORT_SYMBOL(netif_skb_features);
static int xmit_one(struct sk_buff *skb, struct net_device *dev,
- struct netdev_queue *txq)
+ struct netdev_queue *txq, bool more)
{
unsigned int len;
int rc;
@@ -2610,7 +2610,7 @@ static int xmit_one(struct sk_buff *skb, struct net_device *dev,
len = skb->len;
trace_net_dev_start_xmit(skb, dev);
- rc = netdev_start_xmit(skb, dev, txq, false);
+ rc = netdev_start_xmit(skb, dev, txq, more);
trace_net_dev_xmit(skb, rc, dev, len);
return rc;
@@ -2626,7 +2626,7 @@ static struct sk_buff *xmit_list(struct sk_buff *first, struct net_device *dev,
struct sk_buff *next = skb->next;
skb->next = NULL;
- rc = xmit_one(skb, dev, txq);
+ rc = xmit_one(skb, dev, txq, next != NULL);
if (unlikely(!dev_xmit_complete(rc))) {
skb->next = next;
goto out;
@@ -2705,7 +2705,7 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
}
}
- return xmit_one(skb, dev, txq);
+ return xmit_one(skb, dev, txq, false);
}
gso:
--
1.7.11.7
^ permalink raw reply related
* [PATCH 4/9] net: Pass a "more" indication down into netdev_start_xmit() code paths.
From: David Miller @ 2014-09-01 22:24 UTC (permalink / raw)
To: netdev
For now it will always be false.
Signed-off-by: David S. Miller <davem@davemloft.net>
---
drivers/net/wan/dlci.c | 2 +-
include/linux/netdevice.h | 9 +++++----
net/atm/mpc.c | 2 +-
net/core/dev.c | 2 +-
net/core/netpoll.c | 2 +-
net/core/pktgen.c | 2 +-
net/packet/af_packet.c | 2 +-
net/sched/sch_teql.c | 3 ++-
8 files changed, 13 insertions(+), 11 deletions(-)
diff --git a/drivers/net/wan/dlci.c b/drivers/net/wan/dlci.c
index 6427e82..ae6ecf4 100644
--- a/drivers/net/wan/dlci.c
+++ b/drivers/net/wan/dlci.c
@@ -194,7 +194,7 @@ static netdev_tx_t dlci_transmit(struct sk_buff *skb, struct net_device *dev)
if (skb) {
struct netdev_queue *txq = skb_get_tx_queue(dev, skb);
- netdev_start_xmit(skb, dlp->slave, txq);
+ netdev_start_xmit(skb, dlp->slave, txq, false);
}
return NETDEV_TX_OK;
}
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 1617180..5050218 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -3431,19 +3431,20 @@ int __init dev_proc_init(void);
#endif
static inline netdev_tx_t __netdev_start_xmit(const struct net_device_ops *ops,
- struct sk_buff *skb, struct net_device *dev)
+ struct sk_buff *skb, struct net_device *dev,
+ bool more)
{
- skb->xmit_more = 0;
+ skb->xmit_more = more ? 1 : 0;
return ops->ndo_start_xmit(skb, dev);
}
static inline netdev_tx_t netdev_start_xmit(struct sk_buff *skb, struct net_device *dev,
- struct netdev_queue *txq)
+ struct netdev_queue *txq, bool more)
{
const struct net_device_ops *ops = dev->netdev_ops;
int rc;
- rc = __netdev_start_xmit(ops, skb, dev);
+ rc = __netdev_start_xmit(ops, skb, dev, more);
if (rc == NETDEV_TX_OK)
txq_trans_update(txq);
diff --git a/net/atm/mpc.c b/net/atm/mpc.c
index d662da1..0e98222 100644
--- a/net/atm/mpc.c
+++ b/net/atm/mpc.c
@@ -599,7 +599,7 @@ static netdev_tx_t mpc_send_packet(struct sk_buff *skb,
}
non_ip:
- return __netdev_start_xmit(mpc->old_ops, skb, dev);
+ return __netdev_start_xmit(mpc->old_ops, skb, dev, false);
}
static int atm_mpoa_vcc_attach(struct atm_vcc *vcc, void __user *arg)
diff --git a/net/core/dev.c b/net/core/dev.c
index ab7bb80..f0ed5a6 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2610,7 +2610,7 @@ static int xmit_one(struct sk_buff *skb, struct net_device *dev,
len = skb->len;
trace_net_dev_start_xmit(skb, dev);
- rc = netdev_start_xmit(skb, dev, txq);
+ rc = netdev_start_xmit(skb, dev, txq, false);
trace_net_dev_xmit(skb, rc, dev, len);
return rc;
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index 05bc57e..e6645b4 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -91,7 +91,7 @@ static int netpoll_start_xmit(struct sk_buff *skb, struct net_device *dev,
skb->vlan_tci = 0;
}
- status = netdev_start_xmit(skb, dev, txq);
+ status = netdev_start_xmit(skb, dev, txq, false);
out:
return status;
diff --git a/net/core/pktgen.c b/net/core/pktgen.c
index 34bd2ff..5b36a94 100644
--- a/net/core/pktgen.c
+++ b/net/core/pktgen.c
@@ -3335,7 +3335,7 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev)
goto unlock;
}
atomic_inc(&(pkt_dev->skb->users));
- ret = netdev_start_xmit(pkt_dev->skb, odev, txq);
+ ret = netdev_start_xmit(pkt_dev->skb, odev, txq, false);
switch (ret) {
case NETDEV_TX_OK:
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index fe305a0..87d20f4 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -259,7 +259,7 @@ static int packet_direct_xmit(struct sk_buff *skb)
HARD_TX_LOCK(dev, txq, smp_processor_id());
if (!netif_xmit_frozen_or_drv_stopped(txq))
- ret = netdev_start_xmit(skb, dev, txq);
+ ret = netdev_start_xmit(skb, dev, txq, false);
HARD_TX_UNLOCK(dev, txq);
local_bh_enable();
diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c
index 193dc2c..aaa8d03 100644
--- a/net/sched/sch_teql.c
+++ b/net/sched/sch_teql.c
@@ -316,7 +316,8 @@ restart:
unsigned int length = qdisc_pkt_len(skb);
if (!netif_xmit_frozen_or_stopped(slave_txq) &&
- netdev_start_xmit(skb, slave, slave_txq) == NETDEV_TX_OK) {
+ netdev_start_xmit(skb, slave, slave_txq, false) ==
+ NETDEV_TX_OK) {
__netif_tx_unlock(slave_txq);
master->slaves = NEXT_SLAVE(q);
netif_wake_queue(dev);
--
1.7.11.7
^ permalink raw reply related
* [PATCH 3/9] net: Move main gso loop out of dev_hard_start_xmit() into helper.
From: David Miller @ 2014-09-01 22:24 UTC (permalink / raw)
To: netdev
There is a slight policy change happening here as well.
The previous code would drop the entire rest of the GSO skb if any of
them got, for example, a congestion notification.
That makes no sense, anything NET_XMIT_MASK and below is something
like congestion or policing. And in the congestion case it doesn't
even mean the packet was actually dropped.
Just continue until dev_xmit_complete() evaluates to false.
Signed-off-by: David S. Miller <davem@davemloft.net>
---
net/core/dev.c | 48 +++++++++++++++++++++++++++++-------------------
1 file changed, 29 insertions(+), 19 deletions(-)
diff --git a/net/core/dev.c b/net/core/dev.c
index 0fde7d2..ab7bb80 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2616,6 +2616,34 @@ static int xmit_one(struct sk_buff *skb, struct net_device *dev,
return rc;
}
+static struct sk_buff *xmit_list(struct sk_buff *first, struct net_device *dev,
+ struct netdev_queue *txq, int *ret)
+{
+ struct sk_buff *skb = first;
+ int rc = NETDEV_TX_OK;
+
+ while (skb) {
+ struct sk_buff *next = skb->next;
+
+ skb->next = NULL;
+ rc = xmit_one(skb, dev, txq);
+ if (unlikely(!dev_xmit_complete(rc))) {
+ skb->next = next;
+ goto out;
+ }
+
+ skb = next;
+ if (netif_xmit_stopped(txq) && skb) {
+ rc = NETDEV_TX_BUSY;
+ break;
+ }
+ }
+
+out:
+ *ret = rc;
+ return skb;
+}
+
int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
struct netdev_queue *txq)
{
@@ -2681,25 +2709,7 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
}
gso:
- do {
- struct sk_buff *nskb = skb->next;
-
- skb->next = nskb->next;
- nskb->next = NULL;
-
- rc = xmit_one(nskb, dev, txq);
- if (unlikely(rc != NETDEV_TX_OK)) {
- if (rc & ~NETDEV_TX_MASK)
- goto out_kfree_gso_skb;
- nskb->next = skb->next;
- skb->next = nskb;
- return rc;
- }
- if (unlikely(netif_xmit_stopped(txq) && skb->next))
- return NETDEV_TX_BUSY;
- } while (skb->next);
-
-out_kfree_gso_skb:
+ skb->next = xmit_list(skb->next, dev, txq, &rc);
if (likely(skb->next == NULL)) {
skb->destructor = DEV_GSO_CB(skb)->destructor;
consume_skb(skb);
--
1.7.11.7
^ permalink raw reply related
* [PATCH 2/9] net: Create xmit_one() helper for dev_hard_start_xmit()
From: David Miller @ 2014-09-01 22:24 UTC (permalink / raw)
To: netdev
Hopefully making the code a bit easier to read and digest.
Signed-off-by: David S. Miller <davem@davemloft.net>
---
net/core/dev.c | 35 +++++++++++++++++++----------------
1 file changed, 19 insertions(+), 16 deletions(-)
diff --git a/net/core/dev.c b/net/core/dev.c
index 6392ada..0fde7d2 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2599,11 +2599,27 @@ netdev_features_t netif_skb_features(struct sk_buff *skb)
}
EXPORT_SYMBOL(netif_skb_features);
+static int xmit_one(struct sk_buff *skb, struct net_device *dev,
+ struct netdev_queue *txq)
+{
+ unsigned int len;
+ int rc;
+
+ if (!list_empty(&ptype_all))
+ dev_queue_xmit_nit(skb, dev);
+
+ len = skb->len;
+ trace_net_dev_start_xmit(skb, dev);
+ rc = netdev_start_xmit(skb, dev, txq);
+ trace_net_dev_xmit(skb, rc, dev, len);
+
+ return rc;
+}
+
int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
struct netdev_queue *txq)
{
int rc = NETDEV_TX_OK;
- unsigned int skb_len;
if (likely(!skb->next)) {
netdev_features_t features;
@@ -2661,14 +2677,7 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
}
}
- if (!list_empty(&ptype_all))
- dev_queue_xmit_nit(skb, dev);
-
- skb_len = skb->len;
- trace_net_dev_start_xmit(skb, dev);
- rc = netdev_start_xmit(skb, dev, txq);
- trace_net_dev_xmit(skb, rc, dev, skb_len);
- return rc;
+ return xmit_one(skb, dev, txq);
}
gso:
@@ -2678,13 +2687,7 @@ gso:
skb->next = nskb->next;
nskb->next = NULL;
- if (!list_empty(&ptype_all))
- dev_queue_xmit_nit(nskb, dev);
-
- skb_len = nskb->len;
- trace_net_dev_start_xmit(nskb, dev);
- rc = netdev_start_xmit(nskb, dev, txq);
- trace_net_dev_xmit(nskb, rc, dev, skb_len);
+ rc = xmit_one(nskb, dev, txq);
if (unlikely(rc != NETDEV_TX_OK)) {
if (rc & ~NETDEV_TX_MASK)
goto out_kfree_gso_skb;
--
1.7.11.7
^ permalink raw reply related
* [PATCH 1/9] net: Do txq_trans_update() in netdev_start_xmit()
From: David Miller @ 2014-09-01 22:24 UTC (permalink / raw)
To: netdev
That way we don't have to audit every call site to make sure it is
doing this properly.
Signed-off-by: David S. Miller <davem@davemloft.net>
---
drivers/net/wan/dlci.c | 6 ++++--
include/linux/netdevice.h | 10 ++++++++--
net/core/dev.c | 7 ++-----
net/core/netpoll.c | 4 +---
net/core/pktgen.c | 3 +--
net/packet/af_packet.c | 7 ++-----
net/sched/sch_teql.c | 3 +--
7 files changed, 19 insertions(+), 21 deletions(-)
diff --git a/drivers/net/wan/dlci.c b/drivers/net/wan/dlci.c
index 81b22a1..6427e82 100644
--- a/drivers/net/wan/dlci.c
+++ b/drivers/net/wan/dlci.c
@@ -192,8 +192,10 @@ static netdev_tx_t dlci_transmit(struct sk_buff *skb, struct net_device *dev)
{
struct dlci_local *dlp = netdev_priv(dev);
- if (skb)
- netdev_start_xmit(skb, dlp->slave);
+ if (skb) {
+ struct netdev_queue *txq = skb_get_tx_queue(dev, skb);
+ netdev_start_xmit(skb, dlp->slave, txq);
+ }
return NETDEV_TX_OK;
}
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 456eb1f..1617180 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -3437,11 +3437,17 @@ static inline netdev_tx_t __netdev_start_xmit(const struct net_device_ops *ops,
return ops->ndo_start_xmit(skb, dev);
}
-static inline netdev_tx_t netdev_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static inline netdev_tx_t netdev_start_xmit(struct sk_buff *skb, struct net_device *dev,
+ struct netdev_queue *txq)
{
const struct net_device_ops *ops = dev->netdev_ops;
+ int rc;
- return __netdev_start_xmit(ops, skb, dev);
+ rc = __netdev_start_xmit(ops, skb, dev);
+ if (rc == NETDEV_TX_OK)
+ txq_trans_update(txq);
+
+ return rc;
}
int netdev_class_create_file_ns(struct class_attribute *class_attr,
diff --git a/net/core/dev.c b/net/core/dev.c
index a6077ef..6392ada 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2666,10 +2666,8 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
skb_len = skb->len;
trace_net_dev_start_xmit(skb, dev);
- rc = netdev_start_xmit(skb, dev);
+ rc = netdev_start_xmit(skb, dev, txq);
trace_net_dev_xmit(skb, rc, dev, skb_len);
- if (rc == NETDEV_TX_OK)
- txq_trans_update(txq);
return rc;
}
@@ -2685,7 +2683,7 @@ gso:
skb_len = nskb->len;
trace_net_dev_start_xmit(nskb, dev);
- rc = netdev_start_xmit(nskb, dev);
+ rc = netdev_start_xmit(nskb, dev, txq);
trace_net_dev_xmit(nskb, rc, dev, skb_len);
if (unlikely(rc != NETDEV_TX_OK)) {
if (rc & ~NETDEV_TX_MASK)
@@ -2694,7 +2692,6 @@ gso:
skb->next = nskb;
return rc;
}
- txq_trans_update(txq);
if (unlikely(netif_xmit_stopped(txq) && skb->next))
return NETDEV_TX_BUSY;
} while (skb->next);
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index 12b1df9..05bc57e 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -91,9 +91,7 @@ static int netpoll_start_xmit(struct sk_buff *skb, struct net_device *dev,
skb->vlan_tci = 0;
}
- status = netdev_start_xmit(skb, dev);
- if (status == NETDEV_TX_OK)
- txq_trans_update(txq);
+ status = netdev_start_xmit(skb, dev, txq);
out:
return status;
diff --git a/net/core/pktgen.c b/net/core/pktgen.c
index d81b540..34bd2ff 100644
--- a/net/core/pktgen.c
+++ b/net/core/pktgen.c
@@ -3335,11 +3335,10 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev)
goto unlock;
}
atomic_inc(&(pkt_dev->skb->users));
- ret = netdev_start_xmit(pkt_dev->skb, odev);
+ ret = netdev_start_xmit(pkt_dev->skb, odev, txq);
switch (ret) {
case NETDEV_TX_OK:
- txq_trans_update(txq);
pkt_dev->last_ok = 1;
pkt_dev->sofar++;
pkt_dev->seq_num++;
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index b7a7f5a..fe305a0 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -258,11 +258,8 @@ static int packet_direct_xmit(struct sk_buff *skb)
local_bh_disable();
HARD_TX_LOCK(dev, txq, smp_processor_id());
- if (!netif_xmit_frozen_or_drv_stopped(txq)) {
- ret = netdev_start_xmit(skb, dev);
- if (ret == NETDEV_TX_OK)
- txq_trans_update(txq);
- }
+ if (!netif_xmit_frozen_or_drv_stopped(txq))
+ ret = netdev_start_xmit(skb, dev, txq);
HARD_TX_UNLOCK(dev, txq);
local_bh_enable();
diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c
index 64cd93c..193dc2c 100644
--- a/net/sched/sch_teql.c
+++ b/net/sched/sch_teql.c
@@ -316,8 +316,7 @@ restart:
unsigned int length = qdisc_pkt_len(skb);
if (!netif_xmit_frozen_or_stopped(slave_txq) &&
- netdev_start_xmit(skb, slave) == NETDEV_TX_OK) {
- txq_trans_update(slave_txq);
+ netdev_start_xmit(skb, slave, slave_txq) == NETDEV_TX_OK) {
__netif_tx_unlock(slave_txq);
master->slaves = NEXT_SLAVE(q);
netif_wake_queue(dev);
--
1.7.11.7
^ permalink raw reply related
* [PATCH 0/9] Make dev_hard_start_xmit() work fundamentall on lists
From: David Miller @ 2014-09-01 22:24 UTC (permalink / raw)
To: netdev
After this patch set, dev_hard_start_xmit() will work fundemantally
on any and all SKB lists.
This opens the path for a clean implementation of pulling multiple
packets out during qdisc_restart(), and then passing that blob
in one shot to dev_hard_start_xmit().
There were two main architectural blockers to this:
1) The GSO handling, we kept the original GSO head SKB around
simply because dev_hard_start_xmit() had no way to communicate
to the caller how far into the segmented list it was able to
go. Now it can, so the head GSO can be liberated immediately.
All of the special GSO head SKB destructor et al. handling goes
away too.
2) Validate of VLAN, CSUM, and segmentation characteristics was being
performed inside of dev_hard_start_xmit(). If want to truly batch,
we have to let the higher levels to this. In particular, this is
now dequeue_skb()'s job.
And with those two issues out of the way, it should now be trivial to
build experiments on top of this patch set, all of the framework
should be there now. You could do something as simple as:
skb = q->dequeue(q);
if (skb)
skb = validate_xmit_skb(skb, qdisc_dev(q));
if (skb) {
struct sk_buff *new, *head = skb;
int limit = 5;
do {
new = q->dequeue(q);
if (new)
new = validate_xmit_skb(new, qdisc_dev(q));
if (new) {
skb->next = new;
skb = new;
}
} while (new && --limit);
skb = head;
}
inside of the else branch of dequeue_skb().
Signed-off-by: David S. Miller <davem@davemloft.net>
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox