diff options
-rw-r--r-- | include/linux/netdevice.h | 43 | ||||
-rw-r--r-- | net/core/dev.c | 32 | ||||
-rw-r--r-- | net/sched/sch_generic.c | 9 |
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 | |||
83 | enum netdev_tx { | 103 | enum 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 | }; |
88 | typedef enum netdev_tx netdev_tx_t; | 109 | typedef 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; | 1819 | out_kfree_gso_skb: |
1818 | 1820 | if (likely(skb->next == NULL)) | |
1821 | skb->destructor = DEV_GSO_CB(skb)->destructor; | ||
1819 | out_kfree_skb: | 1822 | out_kfree_skb: |
1820 | kfree_skb(skb); | 1823 | kfree_skb(skb); |
1821 | return NETDEV_TX_OK; | 1824 | return rc; |
1822 | } | 1825 | } |
1823 | 1826 | ||
1824 | static u32 skb_tx_hashrnd; | 1827 | static 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 | ||
1912 | static 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); |