aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/netdevice.h43
-rw-r--r--net/core/dev.c32
-rw-r--r--net/sched/sch_generic.c9
3 files changed, 66 insertions, 18 deletions
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 083b5989cecb..8b266390b9e2 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -63,27 +63,48 @@ struct wireless_dev;
63#define HAVE_FREE_NETDEV /* free_netdev() */ 63#define HAVE_FREE_NETDEV /* free_netdev() */
64#define HAVE_NETDEV_PRIV /* netdev_priv() */ 64#define HAVE_NETDEV_PRIV /* netdev_priv() */
65 65
66#define NET_XMIT_SUCCESS 0 66/*
67#define NET_XMIT_DROP 1 /* skb dropped */ 67 * Transmit return codes: transmit return codes originate from three different
68#define NET_XMIT_CN 2 /* congestion notification */ 68 * namespaces:
69#define NET_XMIT_POLICED 3 /* skb is shot by police */ 69 *
70#define NET_XMIT_MASK 0xFFFF /* qdisc flags in net/sch_generic.h */ 70 * - qdisc return codes
71 * - driver transmit return codes
72 * - errno values
73 *
74 * Drivers are allowed to return any one of those in their hard_start_xmit()
75 * function. Real network devices commonly used with qdiscs should only return
76 * the driver transmit return codes though - when qdiscs are used, the actual
77 * transmission happens asynchronously, so the value is not propagated to
78 * higher layers. Virtual network devices transmit synchronously, in this case
79 * the driver transmit return codes are consumed by dev_queue_xmit(), all
80 * others are propagated to higher layers.
81 */
82
83/* qdisc ->enqueue() return codes. */
84#define NET_XMIT_SUCCESS 0x00
85#define NET_XMIT_DROP 0x10 /* skb dropped */
86#define NET_XMIT_CN 0x20 /* congestion notification */
87#define NET_XMIT_POLICED 0x30 /* skb is shot by police */
88#define NET_XMIT_MASK 0xf0 /* qdisc flags in net/sch_generic.h */
71 89
72/* Backlog congestion levels */ 90/* Backlog congestion levels */
73#define NET_RX_SUCCESS 0 /* keep 'em coming, baby */ 91#define NET_RX_SUCCESS 0 /* keep 'em coming, baby */
74#define NET_RX_DROP 1 /* packet dropped */ 92#define NET_RX_DROP 1 /* packet dropped */
75 93
76/* NET_XMIT_CN is special. It does not guarantee that this packet is lost. It 94/* NET_XMIT_CN is special. It does not guarantee that this packet is lost. It
77 * indicates that the device will soon be dropping packets, or already drops 95 * indicates that the device will soon be dropping packets, or already drops
78 * some packets of the same priority; prompting us to send less aggressively. */ 96 * some packets of the same priority; prompting us to send less aggressively. */
79#define net_xmit_eval(e) ((e) == NET_XMIT_CN? 0 : (e)) 97#define net_xmit_eval(e) ((e) == NET_XMIT_CN ? 0 : (e))
80#define net_xmit_errno(e) ((e) != NET_XMIT_CN ? -ENOBUFS : 0) 98#define net_xmit_errno(e) ((e) != NET_XMIT_CN ? -ENOBUFS : 0)
81 99
82/* Driver transmit return codes */ 100/* Driver transmit return codes */
101#define NETDEV_TX_MASK 0xf
102
83enum netdev_tx { 103enum netdev_tx {
84 NETDEV_TX_OK = 0, /* driver took care of packet */ 104 __NETDEV_TX_MIN = INT_MIN, /* make sure enum is signed */
85 NETDEV_TX_BUSY, /* driver tx path was busy*/ 105 NETDEV_TX_OK = 0, /* driver took care of packet */
86 NETDEV_TX_LOCKED = -1, /* driver tx lock was already taken */ 106 NETDEV_TX_BUSY = 1, /* driver tx path was busy*/
107 NETDEV_TX_LOCKED = 2, /* driver tx lock was already taken */
87}; 108};
88typedef enum netdev_tx netdev_tx_t; 109typedef enum netdev_tx netdev_tx_t;
89 110
diff --git a/net/core/dev.c b/net/core/dev.c
index ad8e320ceba7..548340b57296 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1757,7 +1757,7 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
1757 struct netdev_queue *txq) 1757 struct netdev_queue *txq)
1758{ 1758{
1759 const struct net_device_ops *ops = dev->netdev_ops; 1759 const struct net_device_ops *ops = dev->netdev_ops;
1760 int rc; 1760 int rc = NETDEV_TX_OK;
1761 1761
1762 if (likely(!skb->next)) { 1762 if (likely(!skb->next)) {
1763 if (!list_empty(&ptype_all)) 1763 if (!list_empty(&ptype_all))
@@ -1805,6 +1805,8 @@ gso:
1805 nskb->next = NULL; 1805 nskb->next = NULL;
1806 rc = ops->ndo_start_xmit(nskb, dev); 1806 rc = ops->ndo_start_xmit(nskb, dev);
1807 if (unlikely(rc != NETDEV_TX_OK)) { 1807 if (unlikely(rc != NETDEV_TX_OK)) {
1808 if (rc & ~NETDEV_TX_MASK)
1809 goto out_kfree_gso_skb;
1808 nskb->next = skb->next; 1810 nskb->next = skb->next;
1809 skb->next = nskb; 1811 skb->next = nskb;
1810 return rc; 1812 return rc;
@@ -1814,11 +1816,12 @@ gso:
1814 return NETDEV_TX_BUSY; 1816 return NETDEV_TX_BUSY;
1815 } while (skb->next); 1817 } while (skb->next);
1816 1818
1817 skb->destructor = DEV_GSO_CB(skb)->destructor; 1819out_kfree_gso_skb:
1818 1820 if (likely(skb->next == NULL))
1821 skb->destructor = DEV_GSO_CB(skb)->destructor;
1819out_kfree_skb: 1822out_kfree_skb:
1820 kfree_skb(skb); 1823 kfree_skb(skb);
1821 return NETDEV_TX_OK; 1824 return rc;
1822} 1825}
1823 1826
1824static u32 skb_tx_hashrnd; 1827static u32 skb_tx_hashrnd;
@@ -1906,6 +1909,23 @@ static inline int __dev_xmit_skb(struct sk_buff *skb, struct Qdisc *q,
1906 return rc; 1909 return rc;
1907} 1910}
1908 1911
1912static inline bool dev_xmit_complete(int rc)
1913{
1914 /* successful transmission */
1915 if (rc == NETDEV_TX_OK)
1916 return true;
1917
1918 /* error while transmitting, driver consumed skb */
1919 if (rc < 0)
1920 return true;
1921
1922 /* error while queueing to a different device, driver consumed skb */
1923 if (rc & NET_XMIT_MASK)
1924 return true;
1925
1926 return false;
1927}
1928
1909/** 1929/**
1910 * dev_queue_xmit - transmit a buffer 1930 * dev_queue_xmit - transmit a buffer
1911 * @skb: buffer to transmit 1931 * @skb: buffer to transmit
@@ -2003,8 +2023,8 @@ gso:
2003 HARD_TX_LOCK(dev, txq, cpu); 2023 HARD_TX_LOCK(dev, txq, cpu);
2004 2024
2005 if (!netif_tx_queue_stopped(txq)) { 2025 if (!netif_tx_queue_stopped(txq)) {
2006 rc = NET_XMIT_SUCCESS; 2026 rc = dev_hard_start_xmit(skb, dev, txq);
2007 if (!dev_hard_start_xmit(skb, dev, txq)) { 2027 if (dev_xmit_complete(rc)) {
2008 HARD_TX_UNLOCK(dev, txq); 2028 HARD_TX_UNLOCK(dev, txq);
2009 goto out; 2029 goto out;
2010 } 2030 }
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index 4ae6aa562f2b..b13821ad2fb6 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -120,8 +120,15 @@ int sch_direct_xmit(struct sk_buff *skb, struct Qdisc *q,
120 120
121 HARD_TX_LOCK(dev, txq, smp_processor_id()); 121 HARD_TX_LOCK(dev, txq, smp_processor_id());
122 if (!netif_tx_queue_stopped(txq) && 122 if (!netif_tx_queue_stopped(txq) &&
123 !netif_tx_queue_frozen(txq)) 123 !netif_tx_queue_frozen(txq)) {
124 ret = dev_hard_start_xmit(skb, dev, txq); 124 ret = dev_hard_start_xmit(skb, dev, txq);
125
126 /* an error implies that the skb was consumed */
127 if (ret < 0)
128 ret = NETDEV_TX_OK;
129 /* all NET_XMIT codes map to NETDEV_TX_OK */
130 ret &= ~NET_XMIT_MASK;
131 }
125 HARD_TX_UNLOCK(dev, txq); 132 HARD_TX_UNLOCK(dev, txq);
126 133
127 spin_lock(root_lock); 134 spin_lock(root_lock);