* Re: [PATCHES] TX batching
From: Jeff Garzik @ 2007-09-23 18:19 UTC (permalink / raw)
To: hadi
Cc: David Miller, krkumar2, johnpol, herbert, kaber, shemminger,
jagana, Robert.Olsson, rick.jones2, xma, gaagaan, netdev, rdreier,
peter.p.waskiewicz.jr, mcarlson, mchan, general, kumarkr, tgraf,
randy.dunlap, sri
In-Reply-To: <1190569987.4256.52.camel@localhost>
jamal wrote:
> More patches to follow - i didnt want to overload people by dumping
> too many patches. Most of these patches below are ready to go; some are
> need some testing and others need a little porting from an earlier
> kernel:
> - tg3 driver (tested and works well, but dont want to send
> - tun driver
> - pktgen
> - netiron driver
> - e1000 driver
You should post at least a couple driver patches to see how its used on
Real Hardware(tm)... :)
The batching idea has always seemed like a no-brainer to me, so I'm very
interested to see how this turns out.
Jeff
^ permalink raw reply
* [ofa-general] Re: [PATCHES] TX batching
From: jamal @ 2007-09-23 19:11 UTC (permalink / raw)
To: Jeff Garzik
Cc: johnpol, peter.p.waskiewicz.jr, kumarkr, herbert, gaagaan,
Robert.Olsson, netdev, rdreier, mcarlson, kaber, jagana, general,
mchan, tgraf, randy.dunlap, sri, shemminger, David Miller
In-Reply-To: <46F6AE18.7080708@garzik.org>
[-- Attachment #1: Type: text/plain, Size: 599 bytes --]
On Sun, 2007-23-09 at 14:19 -0400, Jeff Garzik wrote:
>
> You should post at least a couple driver patches to see how its used on
> Real Hardware(tm)... :)
This is the tg3 patch i used for the testing - against whats in Daves
net-2.6.24 tree. Patch may be a bit hard to read.
For an example of an LLTX version look at the e1000 in the older git
tree at:
git://git.kernel.org/pub/scm/linux/kernel/git/hadi/batch-lin26.git
If the intel folks will accept the patch i'd really like to kill
the e1000 LLTX interface.
The tg3 in that tree used the old style batch_xmit() interface.
cheers,
jamal
[-- Attachment #2: tg3.p --]
[-- Type: text/x-patch, Size: 16359 bytes --]
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index d4ac6e9..ba0b49e 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -3103,6 +3103,13 @@ static inline u32 tg3_tx_avail(struct tg3 *tp)
((tp->tx_prod - tp->tx_cons) & (TG3_TX_RING_SIZE - 1)));
}
+static inline void tg3_set_win(struct tg3 *tp)
+{
+ tp->dev->xmit_win = tg3_tx_avail(tp) - (MAX_SKB_FRAGS + 1);
+ if (tp->dev->xmit_win < 1)
+ tp->dev->xmit_win = 1;
+}
+
/* Tigon3 never reports partial packet sends. So we do not
* need special logic to handle SKBs that have not had all
* of their frags sent yet, like SunGEM does.
@@ -3165,8 +3172,10 @@ static void tg3_tx(struct tg3 *tp)
(tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH(tp)))) {
netif_tx_lock(tp->dev);
if (netif_queue_stopped(tp->dev) &&
- (tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH(tp)))
+ (tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH(tp))) {
+ tg3_set_win(tp);
netif_wake_queue(tp->dev);
+ }
netif_tx_unlock(tp->dev);
}
}
@@ -3910,47 +3919,67 @@ static void tg3_set_txd(struct tg3 *tp, int entry,
txd->vlan_tag = vlan_tag << TXD_VLAN_TAG_SHIFT;
}
-/* hard_start_xmit for devices that don't have any bugs and
- * support TG3_FLG2_HW_TSO_2 only.
- */
-static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
+struct tg3_tx_cbdata {
+ u32 base_flags;
+ unsigned int mss;
+};
+#define TG3_SKB_CB(__skb) ((struct tg3_tx_cbdata *)&((__skb)->cb[0]))
+#define NETDEV_TX_DROPPED -5
+
+static int tg3_prep_bug_frame(struct sk_buff *skb, struct net_device *dev)
{
+ struct tg3_tx_cbdata *cb = TG3_SKB_CB(skb);
struct tg3 *tp = netdev_priv(dev);
- dma_addr_t mapping;
- u32 len, entry, base_flags, mss;
-
- len = skb_headlen(skb);
+ u32 vlantag = 0;
- /* We are running in BH disabled context with netif_tx_lock
- * and TX reclaim runs via tp->napi.poll inside of a software
- * interrupt. Furthermore, IRQ processing runs lockless so we have
- * no IRQ context deadlocks to worry about either. Rejoice!
- */
- if (unlikely(tg3_tx_avail(tp) <= (skb_shinfo(skb)->nr_frags + 1))) {
- if (!netif_queue_stopped(dev)) {
- netif_stop_queue(dev);
+#if TG3_VLAN_TAG_USED
+ if (tp->vlgrp != NULL && vlan_tx_tag_present(skb))
+ vlantag = (TXD_FLAG_VLAN | (vlan_tx_tag_get(skb) << 16));
+#endif
- /* This is a hard error, log it. */
- printk(KERN_ERR PFX "%s: BUG! Tx Ring full when "
- "queue awake!\n", dev->name);
+ cb->base_flags = vlantag;
+ cb->mss = skb_shinfo(skb)->gso_size;
+ if (cb->mss != 0) {
+ if (skb_header_cloned(skb) &&
+ pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) {
+ dev_kfree_skb(skb);
+ return NETDEV_TX_DROPPED;
}
- return NETDEV_TX_BUSY;
+
+ cb->base_flags |= (TXD_FLAG_CPU_PRE_DMA |
+ TXD_FLAG_CPU_POST_DMA);
}
- entry = tp->tx_prod;
- base_flags = 0;
- mss = 0;
- if ((mss = skb_shinfo(skb)->gso_size) != 0) {
+ if (skb->ip_summed == CHECKSUM_PARTIAL)
+ cb->base_flags |= TXD_FLAG_TCPUDP_CSUM;
+
+ return NETDEV_TX_OK;
+}
+
+static int tg3_prep_frame(struct sk_buff *skb, struct net_device *dev)
+{
+ struct tg3_tx_cbdata *cb = TG3_SKB_CB(skb);
+ struct tg3 *tp = netdev_priv(dev);
+ u32 vlantag = 0;
+
+#if TG3_VLAN_TAG_USED
+ if (tp->vlgrp != NULL && vlan_tx_tag_present(skb))
+ vlantag = (TXD_FLAG_VLAN | (vlan_tx_tag_get(skb) << 16));
+#endif
+
+ cb->base_flags = vlantag;
+ cb->mss = skb_shinfo(skb)->gso_size;
+ if (cb->mss != 0) {
int tcp_opt_len, ip_tcp_len;
if (skb_header_cloned(skb) &&
pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) {
dev_kfree_skb(skb);
- goto out_unlock;
+ return NETDEV_TX_DROPPED;
}
if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)
- mss |= (skb_headlen(skb) - ETH_HLEN) << 9;
+ cb->mss |= (skb_headlen(skb) - ETH_HLEN) << 9;
else {
struct iphdr *iph = ip_hdr(skb);
@@ -3958,32 +3987,63 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
ip_tcp_len = ip_hdrlen(skb) + sizeof(struct tcphdr);
iph->check = 0;
- iph->tot_len = htons(mss + ip_tcp_len + tcp_opt_len);
- mss |= (ip_tcp_len + tcp_opt_len) << 9;
+ iph->tot_len = htons(cb->mss + ip_tcp_len
+ + tcp_opt_len);
+ cb->mss |= (ip_tcp_len + tcp_opt_len) << 9;
}
- base_flags |= (TXD_FLAG_CPU_PRE_DMA |
+ cb->base_flags |= (TXD_FLAG_CPU_PRE_DMA |
TXD_FLAG_CPU_POST_DMA);
tcp_hdr(skb)->check = 0;
}
else if (skb->ip_summed == CHECKSUM_PARTIAL)
- base_flags |= TXD_FLAG_TCPUDP_CSUM;
-#if TG3_VLAN_TAG_USED
- if (tp->vlgrp != NULL && vlan_tx_tag_present(skb))
- base_flags |= (TXD_FLAG_VLAN |
- (vlan_tx_tag_get(skb) << 16));
-#endif
+ cb->base_flags |= TXD_FLAG_TCPUDP_CSUM;
+
+ return NETDEV_TX_OK;
+}
+
+void tg3_kick_DMA(struct net_device *dev)
+{
+ struct tg3 *tp = netdev_priv(dev);
+ u32 entry = tp->tx_prod;
+
+ /* Packets are ready, update Tx producer idx local and on card. */
+ tw32_tx_mbox((MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW), entry);
+
+ if (unlikely(tg3_tx_avail(tp) <= (MAX_SKB_FRAGS + 1))) {
+ netif_stop_queue(dev);
+ dev->xmit_win = 1;
+ if (tg3_tx_avail(tp) >= TG3_TX_WAKEUP_THRESH(tp)) {
+ tg3_set_win(tp);
+ netif_wake_queue(dev);
+ }
+ } else {
+ tg3_set_win(tp);
+ }
+ mmiowb();
+ dev->trans_start = jiffies;
+}
+
+static int tg3_enqueue(struct sk_buff *skb, struct net_device *dev)
+{
+ struct tg3 *tp = netdev_priv(dev);
+ dma_addr_t mapping;
+ u32 len, entry;
+ struct tg3_tx_cbdata *cb = TG3_SKB_CB(skb);
+
+ entry = tp->tx_prod;
+ len = skb_headlen(skb);
/* Queue skb data, a.k.a. the main skb fragment. */
mapping = pci_map_single(tp->pdev, skb->data, len, PCI_DMA_TODEVICE);
tp->tx_buffers[entry].skb = skb;
pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping);
- tg3_set_txd(tp, entry, mapping, len, base_flags,
- (skb_shinfo(skb)->nr_frags == 0) | (mss << 1));
+ tg3_set_txd(tp, entry, mapping, len, cb->base_flags,
+ (skb_shinfo(skb)->nr_frags == 0) | (cb->mss << 1));
entry = NEXT_TX(entry);
@@ -4005,28 +4065,71 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping);
tg3_set_txd(tp, entry, mapping, len,
- base_flags, (i == last) | (mss << 1));
+ cb->base_flags,
+ (i == last) | (cb->mss << 1));
entry = NEXT_TX(entry);
}
}
- /* Packets are ready, update Tx producer idx local and on card. */
- tw32_tx_mbox((MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW), entry);
-
tp->tx_prod = entry;
- if (unlikely(tg3_tx_avail(tp) <= (MAX_SKB_FRAGS + 1))) {
- netif_stop_queue(dev);
- if (tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH(tp))
- netif_wake_queue(tp->dev);
+ return NETDEV_TX_OK;
+}
+
+/* hard_start_xmit for devices that don't have any bugs and
+ * support TG3_FLG2_HW_TSO_2 only.
+ */
+static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct tg3 *tp = netdev_priv(dev);
+ int ret = tg3_prep_frame(skb, dev);
+ /* XXX: original code did mmiowb(); on failure,
+ * I dont think thats necessary
+ */
+ if (unlikely(ret != NETDEV_TX_OK))
+ return NETDEV_TX_OK;
+
+ /* We are running in BH disabled context with netif_tx_lock
+ * and TX reclaim runs via tp->poll inside of a software
+ * interrupt. Furthermore, IRQ processing runs lockless so we have
+ * no IRQ context deadlocks to worry about either. Rejoice!
+ */
+ if (unlikely(tg3_tx_avail(tp) <= (skb_shinfo(skb)->nr_frags + 1))) {
+ if (!netif_queue_stopped(dev)) {
+ netif_stop_queue(dev);
+ tp->dev->xmit_win = 1;
+
+ /* This is a hard error, log it. */
+ printk(KERN_ERR PFX "%s: BUG! Tx Ring full when "
+ "queue awake!\n", dev->name);
+ }
+ return NETDEV_TX_BUSY;
}
-out_unlock:
- mmiowb();
+ ret = tg3_enqueue(skb, dev);
+ if (ret == NETDEV_TX_OK)
+ tg3_kick_DMA(dev);
- dev->trans_start = jiffies;
+ return ret;
+}
- return NETDEV_TX_OK;
+static int tg3_start_bxmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct tg3 *tp = netdev_priv(dev);
+
+ if (unlikely(tg3_tx_avail(tp) <= (skb_shinfo(skb)->nr_frags + 1))) {
+ if (!netif_queue_stopped(dev)) {
+ netif_stop_queue(dev);
+ dev->xmit_win = 1;
+
+ /* This is a hard error, log it. */
+ printk(KERN_ERR PFX "%s: BUG! Tx Ring full when "
+ "queue awake!\n", dev->name);
+ }
+ return NETDEV_TX_BUSY;
+ }
+
+ return tg3_enqueue(skb, dev);
}
static int tg3_start_xmit_dma_bug(struct sk_buff *, struct net_device *);
@@ -4041,9 +4144,11 @@ static int tg3_tso_bug(struct tg3 *tp, struct sk_buff *skb)
/* Estimate the number of fragments in the worst case */
if (unlikely(tg3_tx_avail(tp) <= (skb_shinfo(skb)->gso_segs * 3))) {
netif_stop_queue(tp->dev);
+ tp->dev->xmit_win = 1;
if (tg3_tx_avail(tp) <= (skb_shinfo(skb)->gso_segs * 3))
return NETDEV_TX_BUSY;
+ tg3_set_win(tp);
netif_wake_queue(tp->dev);
}
@@ -4067,46 +4172,19 @@ tg3_tso_bug_end:
/* hard_start_xmit for devices that have the 4G bug and/or 40-bit bug and
* support TG3_FLG2_HW_TSO_1 or firmware TSO only.
*/
-static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev)
+static int tg3_enqueue_buggy(struct sk_buff *skb, struct net_device *dev)
{
struct tg3 *tp = netdev_priv(dev);
dma_addr_t mapping;
- u32 len, entry, base_flags, mss;
+ u32 len, entry;
int would_hit_hwbug;
+ struct tg3_tx_cbdata *cb = TG3_SKB_CB(skb);
- len = skb_headlen(skb);
-
- /* We are running in BH disabled context with netif_tx_lock
- * and TX reclaim runs via tp->napi.poll inside of a software
- * interrupt. Furthermore, IRQ processing runs lockless so we have
- * no IRQ context deadlocks to worry about either. Rejoice!
- */
- if (unlikely(tg3_tx_avail(tp) <= (skb_shinfo(skb)->nr_frags + 1))) {
- if (!netif_queue_stopped(dev)) {
- netif_stop_queue(dev);
-
- /* This is a hard error, log it. */
- printk(KERN_ERR PFX "%s: BUG! Tx Ring full when "
- "queue awake!\n", dev->name);
- }
- return NETDEV_TX_BUSY;
- }
- entry = tp->tx_prod;
- base_flags = 0;
- if (skb->ip_summed == CHECKSUM_PARTIAL)
- base_flags |= TXD_FLAG_TCPUDP_CSUM;
- mss = 0;
- if ((mss = skb_shinfo(skb)->gso_size) != 0) {
+ if (cb->mss != 0) {
struct iphdr *iph;
int tcp_opt_len, ip_tcp_len, hdr_len;
- if (skb_header_cloned(skb) &&
- pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) {
- dev_kfree_skb(skb);
- goto out_unlock;
- }
-
tcp_opt_len = tcp_optlen(skb);
ip_tcp_len = ip_hdrlen(skb) + sizeof(struct tcphdr);
@@ -4115,15 +4193,13 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev)
(tp->tg3_flags2 & TG3_FLG2_TSO_BUG))
return (tg3_tso_bug(tp, skb));
- base_flags |= (TXD_FLAG_CPU_PRE_DMA |
- TXD_FLAG_CPU_POST_DMA);
iph = ip_hdr(skb);
iph->check = 0;
- iph->tot_len = htons(mss + hdr_len);
+ iph->tot_len = htons(cb->mss + hdr_len);
if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) {
tcp_hdr(skb)->check = 0;
- base_flags &= ~TXD_FLAG_TCPUDP_CSUM;
+ cb->base_flags &= ~TXD_FLAG_TCPUDP_CSUM;
} else
tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr,
iph->daddr, 0,
@@ -4136,22 +4212,19 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev)
int tsflags;
tsflags = (iph->ihl - 5) + (tcp_opt_len >> 2);
- mss |= (tsflags << 11);
+ cb->mss |= (tsflags << 11);
}
} else {
if (tcp_opt_len || iph->ihl > 5) {
int tsflags;
tsflags = (iph->ihl - 5) + (tcp_opt_len >> 2);
- base_flags |= tsflags << 12;
+ cb->base_flags |= tsflags << 12;
}
}
}
-#if TG3_VLAN_TAG_USED
- if (tp->vlgrp != NULL && vlan_tx_tag_present(skb))
- base_flags |= (TXD_FLAG_VLAN |
- (vlan_tx_tag_get(skb) << 16));
-#endif
+ len = skb_headlen(skb);
+ entry = tp->tx_prod;
/* Queue skb data, a.k.a. the main skb fragment. */
mapping = pci_map_single(tp->pdev, skb->data, len, PCI_DMA_TODEVICE);
@@ -4164,8 +4237,8 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev)
if (tg3_4g_overflow_test(mapping, len))
would_hit_hwbug = 1;
- tg3_set_txd(tp, entry, mapping, len, base_flags,
- (skb_shinfo(skb)->nr_frags == 0) | (mss << 1));
+ tg3_set_txd(tp, entry, mapping, len, cb->base_flags,
+ (skb_shinfo(skb)->nr_frags == 0) | (cb->mss << 1));
entry = NEXT_TX(entry);
@@ -4194,10 +4267,11 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev)
if (tp->tg3_flags2 & TG3_FLG2_HW_TSO)
tg3_set_txd(tp, entry, mapping, len,
- base_flags, (i == last)|(mss << 1));
+ cb->base_flags,
+ (i == last)|(cb->mss << 1));
else
tg3_set_txd(tp, entry, mapping, len,
- base_flags, (i == last));
+ cb->base_flags, (i == last));
entry = NEXT_TX(entry);
}
@@ -4214,28 +4288,68 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev)
* failure, silently drop this packet.
*/
if (tigon3_dma_hwbug_workaround(tp, skb, last_plus_one,
- &start, base_flags, mss))
- goto out_unlock;
+ &start, cb->base_flags,
+ cb->mss)) {
+ mmiowb();
+ return NETDEV_TX_OK;
+ }
entry = start;
}
- /* Packets are ready, update Tx producer idx local and on card. */
- tw32_tx_mbox((MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW), entry);
-
tp->tx_prod = entry;
- if (unlikely(tg3_tx_avail(tp) <= (MAX_SKB_FRAGS + 1))) {
- netif_stop_queue(dev);
- if (tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH(tp))
- netif_wake_queue(tp->dev);
+ return NETDEV_TX_OK;
+}
+
+static int tg3_start_bxmit_dma_bug(struct sk_buff *skb, struct net_device *dev)
+{
+ struct tg3 *tp = netdev_priv(dev);
+
+ if (unlikely(tg3_tx_avail(tp) <= (skb_shinfo(skb)->nr_frags + 1))) {
+ if (!netif_queue_stopped(dev)) {
+ netif_stop_queue(dev);
+ dev->xmit_win = 1;
+
+ /* This is a hard error, log it. */
+ printk(KERN_ERR PFX "%s: BUG! Tx Ring full when "
+ "queue awake!\n", dev->name);
+ }
+ return NETDEV_TX_BUSY;
}
-out_unlock:
- mmiowb();
+ return tg3_enqueue_buggy(skb, dev);
+}
- dev->trans_start = jiffies;
+static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev)
+{
+ struct tg3 *tp = netdev_priv(dev);
+ int ret = tg3_prep_bug_frame(skb, dev);
- return NETDEV_TX_OK;
+ if (unlikely(ret != NETDEV_TX_OK))
+ return NETDEV_TX_OK;
+
+ /* We are running in BH disabled context with netif_tx_lock
+ * and TX reclaim runs via tp->poll inside of a software
+ * interrupt. Furthermore, IRQ processing runs lockless so we have
+ * no IRQ context deadlocks to worry about either. Rejoice!
+ */
+ if (unlikely(tg3_tx_avail(tp) <= (skb_shinfo(skb)->nr_frags + 1))) {
+ if (!netif_queue_stopped(dev)) {
+ netif_stop_queue(dev);
+ dev->xmit_win = 1;
+
+ /* This is a hard error, log it. */
+ printk(KERN_ERR PFX "%s: BUG! Tx Ring full when "
+ "queue awake!\n", dev->name);
+ }
+ return NETDEV_TX_BUSY;
+ }
+
+ ret = tg3_enqueue_buggy(skb, dev);
+ if (ret == NETDEV_TX_OK)
+ tg3_kick_DMA(dev);
+
+ return ret;
}
static inline void tg3_set_mtu(struct net_device *dev, struct tg3 *tp,
@@ -11039,15 +11153,19 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
else
tp->tg3_flags &= ~TG3_FLAG_POLL_SERDES;
+ tp->dev->hard_end_xmit = tg3_kick_DMA;
/* All chips before 5787 can get confused if TX buffers
* straddle the 4GB address boundary in some cases.
*/
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
- tp->dev->hard_start_xmit = tg3_start_xmit;
- else
- tp->dev->hard_start_xmit = tg3_start_xmit_dma_bug;
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+ tp->dev->hard_start_xmit = tg3_start_bxmit;
+ tp->dev->hard_prep_xmit = tg3_prep_frame;
+ } else {
+ tp->dev->hard_start_xmit = tg3_start_bxmit_dma_bug;
+ tp->dev->hard_prep_xmit = tg3_prep_bug_frame;
+ }
tp->rx_offset = 2;
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701 &&
@@ -11895,6 +12013,8 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
dev->watchdog_timeo = TG3_TX_TIMEOUT;
dev->change_mtu = tg3_change_mtu;
dev->irq = pdev->irq;
+ dev->features |= NETIF_F_BTX;
+ dev->xmit_win = tp->tx_pending >> 2;
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = tg3_poll_controller;
#endif
[-- Attachment #3: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply related
* [ofa-general] Re: [PATCHES] TX batching
From: Kok, Auke @ 2007-09-23 19:36 UTC (permalink / raw)
To: hadi
Cc: randy.dunlap, Robert.Olsson, gaagaan, kumarkr,
peter.p.waskiewicz.jr, shemminger, johnpol, herbert, Jeff Garzik,
rdreier, mcarlson, general, sri, jagana, mchan, netdev, kaber,
tgraf, David Miller
In-Reply-To: <1190574713.5030.4.camel@localhost>
jamal wrote:
> On Sun, 2007-23-09 at 14:19 -0400, Jeff Garzik wrote:
>
>> You should post at least a couple driver patches to see how its used on
>> Real Hardware(tm)... :)
>
> This is the tg3 patch i used for the testing - against whats in Daves
> net-2.6.24 tree. Patch may be a bit hard to read.
> For an example of an LLTX version look at the e1000 in the older git
> tree at:
> git://git.kernel.org/pub/scm/linux/kernel/git/hadi/batch-lin26.git
>
> If the intel folks will accept the patch i'd really like to kill
> the e1000 LLTX interface.
> The tg3 in that tree used the old style batch_xmit() interface.
please be reminded that we're going to strip down e1000 and most of the features
should go into e1000e, which has much less hardware workarounds. I'm still
reluctant to putting in new stuff in e1000 - I really want to chop it down first ;)
AUke
^ permalink raw reply
* Re: [ofa-general] [PATCH v2] iw_cxgb3: Support "iwarp-only" interfaces to avoid 4-tuple conflicts.
From: Steve Wise @ 2007-09-23 20:33 UTC (permalink / raw)
To: Sean Hefty; +Cc: netdev, rdreier, general, linux-kernel
In-Reply-To: <46E99586.90905@ichips.intel.com>
Sean Hefty wrote:
>> The iWARP driver must translate all listens on address 0.0.0.0 to the
>> set of rdma-only ip addresses for the device in question. This prevents
>> incoming connect requests to the TCP ipaddresses from going up the
>> rdma stack.
>
> I've only given this a high level review at this point, and while the
> patch looks okay on first pass, is there a way to move some of this
> functionality to either the rdma_cm or iw_cm? I don't like the idea of
> every iwarp driver having to implement address/listen list maintenance.
> I may have some ideas after re-examining it.
>
Note: some rnic drivers might want to support this differently. So
maybe we don't want this in the iwcm yet until we see that more iwarp
drivers need exactly the same functionality.
>> Implementation Details:
>
> There are a couple of areas that I made a note to look at in more detail
> (because I didn't understand everything that was happening), but I did
> have one minor nit - most uses of list_del_init can just be list_del.
>
fixed.
^ permalink raw reply
* [ofa-general] [PATCH v3] iw_cxgb3: Support "iwarp-only" interfaces to avoid 4-tuple conflicts.
From: Steve Wise @ 2007-09-23 20:36 UTC (permalink / raw)
To: rdreier, sean.hefty; +Cc: netdev, linux-kernel, general
iw_cxgb3: Support "iwarp-only" interfaces to avoid 4-tuple conflicts.
Version 3:
- don't use list_del_init() where list_del() is sufficient.
Version 2:
- added a per-device mutex for the address and listening endpoints lists.
- wait for all replies if sending multiple passive_open requests to rnic.
- log warning if no addresses are available when a listen is issued.
- tested
---
Design:
The sysadmin creates "for iwarp use only" alias interfaces of the form
"devname:iw*" where devname is the native interface name (eg eth0) for the
iwarp netdev device. The alias label can be anything starting with "iw".
The "iw" immediately after the ':' is the key used by the iw_cxgb3 driver.
EG:
ifconfig eth0 192.168.70.123 up
ifconfig eth0:iw1 192.168.71.123 up
ifconfig eth0:iw2 192.168.72.123 up
In the above example, 192.168.70/24 is for TCP traffic, while
192.168.71/24 and 192.168.72/24 are for iWARP/RDMA use.
The rdma-only interface must be on its own IP subnet. This allows routing
all rdma traffic onto this interface.
The iWARP driver must translate all listens on address 0.0.0.0 to the
set of rdma-only ip addresses for the device in question. This prevents
incoming connect requests to the TCP ipaddresses from going up the
rdma stack.
Implementation Details:
- The iw_cxgb3 driver registers for inetaddr events via
register_inetaddr_notifier(). This allows tracking the iwarp-only
addresses/subnets as they get added and deleted. The iwarp driver
maintains a list of the current iwarp-only addresses.
- The iw_cxgb3 driver builds the list of iwarp-only addresses for its
devices at module insert time. This is needed because the inetaddr
notifier callbacks don't "replay" address-add events when someone
registers. So the driver must build the initial list at module load time.
- When a listen is done on address 0.0.0.0, then the iw_cxgb3 driver
must translate that into a set of listens on the iwarp-only addresses.
This is implemented by maintaining a list of stid/addr entries per
listening endpoint.
- When a new iwarp-only address is added or removed, the iw_cxgb3 driver
must traverse the set of listening endpoints and update them accordingly.
This allows an application to bind to 0.0.0.0 prior to the iwarp-only
interfaces being configured. It also allows changing the iwarp-only set
of addresses and getting the expected behavior for apps already bound
to 0.0.0.0. This is done by maintaining a list of listening endpoints
off the device struct.
- The address list, the listening endpoint list, and each list of
stid/addrs in use per listening endpoint are all protected via a mutex
per iw_cxgb3 device.
Signed-off-by: Steve Wise <swise@opengridcomputing.com>
---
drivers/infiniband/hw/cxgb3/iwch.c | 125 ++++++++++++++++
drivers/infiniband/hw/cxgb3/iwch.h | 11 +
drivers/infiniband/hw/cxgb3/iwch_cm.c | 259 +++++++++++++++++++++++++++------
drivers/infiniband/hw/cxgb3/iwch_cm.h | 15 ++
4 files changed, 360 insertions(+), 50 deletions(-)
diff --git a/drivers/infiniband/hw/cxgb3/iwch.c b/drivers/infiniband/hw/cxgb3/iwch.c
index 0315c9d..d81d46e 100644
--- a/drivers/infiniband/hw/cxgb3/iwch.c
+++ b/drivers/infiniband/hw/cxgb3/iwch.c
@@ -63,6 +63,123 @@ struct cxgb3_client t3c_client = {
static LIST_HEAD(dev_list);
static DEFINE_MUTEX(dev_mutex);
+static void insert_ifa(struct iwch_dev *rnicp, struct in_ifaddr *ifa)
+{
+ struct iwch_addrlist *addr;
+
+ addr = kmalloc(sizeof *addr, GFP_KERNEL);
+ if (!addr) {
+ printk(KERN_ERR MOD "%s - failed to alloc memory!\n",
+ __FUNCTION__);
+ return;
+ }
+ addr->ifa = ifa;
+ mutex_lock(&rnicp->mutex);
+ list_add_tail(&addr->entry, &rnicp->addrlist);
+ mutex_unlock(&rnicp->mutex);
+}
+
+static void remove_ifa(struct iwch_dev *rnicp, struct in_ifaddr *ifa)
+{
+ struct iwch_addrlist *addr, *tmp;
+
+ mutex_lock(&rnicp->mutex);
+ list_for_each_entry_safe(addr, tmp, &rnicp->addrlist, entry) {
+ if (addr->ifa == ifa) {
+ list_del(&addr->entry);
+ kfree(addr);
+ goto out;
+ }
+ }
+out:
+ mutex_unlock(&rnicp->mutex);
+}
+
+static int netdev_is_ours(struct iwch_dev *rnicp, struct net_device *netdev)
+{
+ int i;
+
+ for (i = 0; i < rnicp->rdev.port_info.nports; i++)
+ if (netdev == rnicp->rdev.port_info.lldevs[i])
+ return 1;
+ return 0;
+}
+
+static inline int is_iwarp_label(char *label)
+{
+ char *colon;
+
+ colon = strchr(label, ':');
+ if (colon && !strncmp(colon+1, "iw", 2))
+ return 1;
+ return 0;
+}
+
+static int nb_callback(struct notifier_block *self, unsigned long event,
+ void *ctx)
+{
+ struct in_ifaddr *ifa = ctx;
+ struct iwch_dev *rnicp = container_of(self, struct iwch_dev, nb);
+
+ PDBG("%s rnicp %p event %lx\n", __FUNCTION__, rnicp, event);
+
+ switch (event) {
+ case NETDEV_UP:
+ if (netdev_is_ours(rnicp, ifa->ifa_dev->dev) &&
+ is_iwarp_label(ifa->ifa_label)) {
+ PDBG("%s label %s addr 0x%x added\n",
+ __FUNCTION__, ifa->ifa_label, ifa->ifa_address);
+ insert_ifa(rnicp, ifa);
+ iwch_listeners_add_addr(rnicp, ifa->ifa_address);
+ }
+ break;
+ case NETDEV_DOWN:
+ if (netdev_is_ours(rnicp, ifa->ifa_dev->dev) &&
+ is_iwarp_label(ifa->ifa_label)) {
+ PDBG("%s label %s addr 0x%x deleted\n",
+ __FUNCTION__, ifa->ifa_label, ifa->ifa_address);
+ iwch_listeners_del_addr(rnicp, ifa->ifa_address);
+ remove_ifa(rnicp, ifa);
+ }
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static void delete_addrlist(struct iwch_dev *rnicp)
+{
+ struct iwch_addrlist *addr, *tmp;
+
+ mutex_lock(&rnicp->mutex);
+ list_for_each_entry_safe(addr, tmp, &rnicp->addrlist, entry) {
+ list_del(&addr->entry);
+ kfree(addr);
+ }
+ mutex_unlock(&rnicp->mutex);
+}
+
+static void populate_addrlist(struct iwch_dev *rnicp)
+{
+ int i;
+ struct in_device *indev;
+
+ for (i = 0; i < rnicp->rdev.port_info.nports; i++) {
+ indev = in_dev_get(rnicp->rdev.port_info.lldevs[i]);
+ if (!indev)
+ continue;
+ for_ifa(indev)
+ if (is_iwarp_label(ifa->ifa_label)) {
+ PDBG("%s label %s addr 0x%x added\n",
+ __FUNCTION__, ifa->ifa_label,
+ ifa->ifa_address);
+ insert_ifa(rnicp, ifa);
+ }
+ endfor_ifa(indev);
+ }
+}
+
static void rnic_init(struct iwch_dev *rnicp)
{
PDBG("%s iwch_dev %p\n", __FUNCTION__, rnicp);
@@ -70,6 +187,12 @@ static void rnic_init(struct iwch_dev *r
idr_init(&rnicp->qpidr);
idr_init(&rnicp->mmidr);
spin_lock_init(&rnicp->lock);
+ INIT_LIST_HEAD(&rnicp->addrlist);
+ INIT_LIST_HEAD(&rnicp->listen_eps);
+ mutex_init(&rnicp->mutex);
+ rnicp->nb.notifier_call = nb_callback;
+ populate_addrlist(rnicp);
+ register_inetaddr_notifier(&rnicp->nb);
rnicp->attr.vendor_id = 0x168;
rnicp->attr.vendor_part_id = 7;
@@ -148,6 +271,8 @@ static void close_rnic_dev(struct t3cdev
mutex_lock(&dev_mutex);
list_for_each_entry_safe(dev, tmp, &dev_list, entry) {
if (dev->rdev.t3cdev_p == tdev) {
+ unregister_inetaddr_notifier(&dev->nb);
+ delete_addrlist(dev);
list_del(&dev->entry);
iwch_unregister_device(dev);
cxio_rdev_close(&dev->rdev);
diff --git a/drivers/infiniband/hw/cxgb3/iwch.h b/drivers/infiniband/hw/cxgb3/iwch.h
index caf4e60..7fa0a47 100644
--- a/drivers/infiniband/hw/cxgb3/iwch.h
+++ b/drivers/infiniband/hw/cxgb3/iwch.h
@@ -36,6 +36,8 @@ #include <linux/mutex.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/idr.h>
+#include <linux/notifier.h>
+#include <linux/inetdevice.h>
#include <rdma/ib_verbs.h>
@@ -101,6 +103,11 @@ struct iwch_rnic_attributes {
u32 cq_overflow_detection;
};
+struct iwch_addrlist {
+ struct list_head entry;
+ struct in_ifaddr *ifa;
+};
+
struct iwch_dev {
struct ib_device ibdev;
struct cxio_rdev rdev;
@@ -111,6 +118,10 @@ struct iwch_dev {
struct idr mmidr;
spinlock_t lock;
struct list_head entry;
+ struct notifier_block nb;
+ struct list_head addrlist;
+ struct list_head listen_eps;
+ struct mutex mutex;
};
static inline struct iwch_dev *to_iwch_dev(struct ib_device *ibdev)
diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c
index 1cdfcd4..afc8a48 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_cm.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c
@@ -1127,23 +1127,149 @@ static int act_open_rpl(struct t3cdev *t
return CPL_RET_BUF_DONE;
}
-static int listen_start(struct iwch_listen_ep *ep)
+static int wait_for_reply(struct iwch_ep_common *epc)
+{
+ PDBG("%s ep %p waiting\n", __FUNCTION__, epc);
+ wait_event(epc->waitq, epc->rpl_done);
+ PDBG("%s ep %p done waiting err %d\n", __FUNCTION__, epc, epc->rpl_err);
+ return epc->rpl_err;
+}
+
+static struct iwch_listen_entry *alloc_listener(struct iwch_listen_ep *ep,
+ __be32 addr)
+{
+ struct iwch_dev *h = to_iwch_dev(ep->com.cm_id->device);
+ struct iwch_listen_entry *le;
+
+ le = kmalloc(sizeof *le, GFP_KERNEL);
+ if (!le) {
+ printk(KERN_ERR MOD "%s - failed to alloc memory!\n",
+ __FUNCTION__);
+ return NULL;
+ }
+ le->stid = cxgb3_alloc_stid(h->rdev.t3cdev_p,
+ &t3c_client, ep);
+ if (le->stid == -1) {
+ printk(KERN_ERR MOD "%s - cannot alloc stid.\n",
+ __FUNCTION__);
+ kfree(le);
+ return NULL;
+ }
+ le->addr = addr;
+ PDBG("%s stid %u addr %x port %x\n", __FUNCTION__, le->stid,
+ ntohl(le->addr), ntohs(ep->com.local_addr.sin_port));
+ return le;
+}
+
+static void dealloc_listener(struct iwch_listen_ep *ep,
+ struct iwch_listen_entry *le)
+{
+ PDBG("%s stid %u addr %x port %x\n", __FUNCTION__, le->stid,
+ ntohl(le->addr), ntohs(ep->com.local_addr.sin_port));
+ cxgb3_free_stid(ep->com.tdev, le->stid);
+ kfree(le);
+}
+
+static void dealloc_listener_list(struct iwch_listen_ep *ep)
+{
+ struct iwch_listen_entry *le, *tmp;
+ struct iwch_dev *h = to_iwch_dev(ep->com.cm_id->device);
+
+ mutex_lock(&h->mutex);
+ list_for_each_entry_safe(le, tmp, &ep->listeners, entry) {
+ list_del(&le->entry);
+ dealloc_listener(ep, le);
+ }
+ mutex_unlock(&h->mutex);
+}
+
+static int alloc_listener_list(struct iwch_listen_ep *ep)
+{
+ struct iwch_dev *h = to_iwch_dev(ep->com.cm_id->device);
+ struct iwch_addrlist *addr;
+ struct iwch_listen_entry *le;
+ int err = 0;
+ int added=0;
+ mutex_lock(&h->mutex);
+ list_for_each_entry(addr, &h->addrlist, entry) {
+ if (ep->com.local_addr.sin_addr.s_addr == 0 ||
+ ep->com.local_addr.sin_addr.s_addr ==
+ addr->ifa->ifa_address) {
+ le = alloc_listener(ep, addr->ifa->ifa_address);
+ if (!le)
+ break;
+ list_add_tail(&le->entry, &ep->listeners);
+ added++;
+ }
+ }
+ mutex_unlock(&h->mutex);
+ if (ep->com.local_addr.sin_addr.s_addr != 0 && !added)
+ err = -EADDRNOTAVAIL;
+ if (!err && !added)
+ printk(KERN_WARNING MOD
+ "No RDMA interface found for device %s\n",
+ pci_name(h->rdev.rnic_info.pdev));
+ return err;
+}
+
+static int listen_stop_one(struct iwch_listen_ep *ep, unsigned int stid)
{
struct sk_buff *skb;
- struct cpl_pass_open_req *req;
+ struct cpl_close_listserv_req *req;
+
+ PDBG("%s stid %u\n", __FUNCTION__, stid);
+ skb = get_skb(NULL, sizeof(*req), GFP_KERNEL);
+ if (!skb) {
+ printk(KERN_ERR MOD "%s - failed to alloc skb\n", __FUNCTION__);
+ return -ENOMEM;
+ }
+ req = (struct cpl_close_listserv_req *) skb_put(skb, sizeof(*req));
+ req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
+ req->cpu_idx = 0;
+ OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_CLOSE_LISTSRV_REQ, stid));
+ skb->priority = 1;
+ ep->com.rpl_err = 0;
+ ep->com.rpl_done = 0;
+ cxgb3_ofld_send(ep->com.tdev, skb);
+ return wait_for_reply(&ep->com);
+}
+
+static int listen_stop(struct iwch_listen_ep *ep)
+{
+ struct iwch_listen_entry *le;
+ struct iwch_dev *h = to_iwch_dev(ep->com.cm_id->device);
+ int err = 0;
PDBG("%s ep %p\n", __FUNCTION__, ep);
+ mutex_lock(&h->mutex);
+ list_for_each_entry(le, &ep->listeners, entry) {
+ err = listen_stop_one(ep, le->stid);
+ if (err)
+ break;
+ }
+ mutex_unlock(&h->mutex);
+ return err;
+}
+
+static int listen_start_one(struct iwch_listen_ep *ep, unsigned int stid,
+ __be32 addr, __be16 port)
+{
+ struct sk_buff *skb;
+ struct cpl_pass_open_req *req;
+
+ PDBG("%s stid %u addr %x port %x\n", __FUNCTION__, stid, ntohl(addr),
+ ntohs(port));
skb = get_skb(NULL, sizeof(*req), GFP_KERNEL);
if (!skb) {
- printk(KERN_ERR MOD "t3c_listen_start failed to alloc skb!\n");
+ printk(KERN_ERR MOD "%s - failed to alloc skb\n", __FUNCTION__);
return -ENOMEM;
}
req = (struct cpl_pass_open_req *) skb_put(skb, sizeof(*req));
req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
- OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_PASS_OPEN_REQ, ep->stid));
- req->local_port = ep->com.local_addr.sin_port;
- req->local_ip = ep->com.local_addr.sin_addr.s_addr;
+ OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_PASS_OPEN_REQ, stid));
+ req->local_port = port;
+ req->local_ip = addr;
req->peer_port = 0;
req->peer_ip = 0;
req->peer_netmask = 0;
@@ -1152,8 +1278,32 @@ static int listen_start(struct iwch_list
req->opt1 = htonl(V_CONN_POLICY(CPL_CONN_POLICY_ASK));
skb->priority = 1;
+ ep->com.rpl_err = 0;
+ ep->com.rpl_done = 0;
cxgb3_ofld_send(ep->com.tdev, skb);
- return 0;
+ return wait_for_reply(&ep->com);
+}
+
+static int listen_start(struct iwch_listen_ep *ep)
+{
+ struct iwch_listen_entry *le;
+ struct iwch_dev *h = to_iwch_dev(ep->com.cm_id->device);
+ int err = 0;
+
+ PDBG("%s ep %p\n", __FUNCTION__, ep);
+ mutex_lock(&h->mutex);
+ list_for_each_entry(le, &ep->listeners, entry) {
+ err = listen_start_one(ep, le->stid, le->addr,
+ ep->com.local_addr.sin_port);
+ if (err)
+ goto fail;
+ }
+ mutex_unlock(&h->mutex);
+ return err;
+fail:
+ mutex_unlock(&h->mutex);
+ listen_stop(ep);
+ return err;
}
static int pass_open_rpl(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
@@ -1170,39 +1320,59 @@ static int pass_open_rpl(struct t3cdev *
return CPL_RET_BUF_DONE;
}
-static int listen_stop(struct iwch_listen_ep *ep)
-{
- struct sk_buff *skb;
- struct cpl_close_listserv_req *req;
-
- PDBG("%s ep %p\n", __FUNCTION__, ep);
- skb = get_skb(NULL, sizeof(*req), GFP_KERNEL);
- if (!skb) {
- printk(KERN_ERR MOD "%s - failed to alloc skb\n", __FUNCTION__);
- return -ENOMEM;
- }
- req = (struct cpl_close_listserv_req *) skb_put(skb, sizeof(*req));
- req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
- req->cpu_idx = 0;
- OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_CLOSE_LISTSRV_REQ, ep->stid));
- skb->priority = 1;
- cxgb3_ofld_send(ep->com.tdev, skb);
- return 0;
-}
-
static int close_listsrv_rpl(struct t3cdev *tdev, struct sk_buff *skb,
void *ctx)
{
struct iwch_listen_ep *ep = ctx;
struct cpl_close_listserv_rpl *rpl = cplhdr(skb);
- PDBG("%s ep %p\n", __FUNCTION__, ep);
+ PDBG("%s ep %p stid %u\n", __FUNCTION__, ep, GET_TID(rpl));
+
ep->com.rpl_err = status2errno(rpl->status);
ep->com.rpl_done = 1;
wake_up(&ep->com.waitq);
return CPL_RET_BUF_DONE;
}
+void iwch_listeners_add_addr(struct iwch_dev *rnicp, __be32 addr)
+{
+ struct iwch_listen_ep *listen_ep;
+ struct iwch_listen_entry *le;
+
+ mutex_lock(&rnicp->mutex);
+ list_for_each_entry(listen_ep, &rnicp->listen_eps, entry) {
+ if (listen_ep->com.local_addr.sin_addr.s_addr)
+ continue;
+ le = alloc_listener(listen_ep, addr);
+ if (le) {
+ list_add_tail(&le->entry, &listen_ep->listeners);
+ listen_start_one(listen_ep, le->stid, addr,
+ listen_ep->com.local_addr.sin_port);
+ }
+ }
+ mutex_unlock(&rnicp->mutex);
+}
+
+void iwch_listeners_del_addr(struct iwch_dev *rnicp, __be32 addr)
+{
+ struct iwch_listen_ep *listen_ep;
+ struct iwch_listen_entry *le, *tmp;
+
+ mutex_lock(&rnicp->mutex);
+ list_for_each_entry(listen_ep, &rnicp->listen_eps, entry) {
+ if (listen_ep->com.local_addr.sin_addr.s_addr)
+ continue;
+ list_for_each_entry_safe(le, tmp, &listen_ep->listeners,
+ entry)
+ if (le->addr == addr) {
+ listen_stop_one(listen_ep, le->stid);
+ list_del(&le->entry);
+ dealloc_listener(listen_ep, le);
+ }
+ }
+ mutex_unlock(&rnicp->mutex);
+}
+
static void accept_cr(struct iwch_ep *ep, __be32 peer_ip, struct sk_buff *skb)
{
struct cpl_pass_accept_rpl *rpl;
@@ -1767,8 +1937,7 @@ int iwch_accept_cr(struct iw_cm_id *cm_i
goto err;
/* wait for wr_ack */
- wait_event(ep->com.waitq, ep->com.rpl_done);
- err = ep->com.rpl_err;
+ err = wait_for_reply(&ep->com);
if (err)
goto err;
@@ -1887,31 +2056,23 @@ int iwch_create_listen(struct iw_cm_id *
ep->com.cm_id = cm_id;
ep->backlog = backlog;
ep->com.local_addr = cm_id->local_addr;
+ INIT_LIST_HEAD(&ep->listeners);
- /*
- * Allocate a server TID.
- */
- ep->stid = cxgb3_alloc_stid(h->rdev.t3cdev_p, &t3c_client, ep);
- if (ep->stid == -1) {
- printk(KERN_ERR MOD "%s - cannot alloc atid.\n", __FUNCTION__);
- err = -ENOMEM;
+ err = alloc_listener_list(ep);
+ if (err)
goto fail2;
- }
state_set(&ep->com, LISTEN);
err = listen_start(ep);
- if (err)
- goto fail3;
- /* wait for pass_open_rpl */
- wait_event(ep->com.waitq, ep->com.rpl_done);
- err = ep->com.rpl_err;
if (!err) {
cm_id->provider_data = ep;
+ mutex_lock(&h->mutex);
+ list_add_tail(&ep->entry, &h->listen_eps);
+ mutex_unlock(&h->mutex);
goto out;
}
-fail3:
- cxgb3_free_stid(ep->com.tdev, ep->stid);
+ dealloc_listener_list(ep);
fail2:
cm_id->rem_ref(cm_id);
put_ep(&ep->com);
@@ -1923,18 +2084,20 @@ out:
int iwch_destroy_listen(struct iw_cm_id *cm_id)
{
int err;
+ struct iwch_dev *h = to_iwch_dev(cm_id->device);
struct iwch_listen_ep *ep = to_listen_ep(cm_id);
PDBG("%s ep %p\n", __FUNCTION__, ep);
might_sleep();
+ mutex_lock(&h->mutex);
+ list_del(&ep->entry);
+ mutex_unlock(&h->mutex);
state_set(&ep->com, DEAD);
ep->com.rpl_done = 0;
ep->com.rpl_err = 0;
err = listen_stop(ep);
- wait_event(ep->com.waitq, ep->com.rpl_done);
- cxgb3_free_stid(ep->com.tdev, ep->stid);
- err = ep->com.rpl_err;
+ dealloc_listener_list(ep);
cm_id->rem_ref(cm_id);
put_ep(&ep->com);
return err;
diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.h b/drivers/infiniband/hw/cxgb3/iwch_cm.h
index 6107e7c..23e5a22 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_cm.h
+++ b/drivers/infiniband/hw/cxgb3/iwch_cm.h
@@ -162,10 +162,19 @@ struct iwch_ep_common {
int rpl_err;
};
-struct iwch_listen_ep {
- struct iwch_ep_common com;
+struct iwch_listen_entry {
+ struct list_head entry;
unsigned int stid;
+ __be32 addr;
+};
+
+struct iwch_listen_ep {
+ struct iwch_ep_common com; /* Must be first entry! */
+ struct list_head entry;
+ struct list_head listeners;
int backlog;
+ int listen_count;
+ int listen_rpls;
};
struct iwch_ep {
@@ -222,6 +231,8 @@ int iwch_resume_tid(struct iwch_ep *ep);
void __free_ep(struct kref *kref);
void iwch_rearp(struct iwch_ep *ep);
int iwch_ep_redirect(void *ctx, struct dst_entry *old, struct dst_entry *new, struct l2t_entry *l2t);
+void iwch_listeners_add_addr(struct iwch_dev *rnicp, __be32 addr);
+void iwch_listeners_del_addr(struct iwch_dev *rnicp, __be32 addr);
int __init iwch_cm_init(void);
void __exit iwch_cm_term(void);
^ permalink raw reply related
* Re: bind and O_NONBLOCK
From: Alan Cox @ 2007-09-23 20:43 UTC (permalink / raw)
To: David Miller; +Cc: drepper, johnpol, netdev, alan
In-Reply-To: <20070922.225818.74741259.davem@davemloft.net>
On Sat, Sep 22, 2007 at 10:58:18PM -0700, David Miller wrote:
> From: Ulrich Drepper <drepper@redhat.com>
> Date: Sat, 22 Sep 2007 10:11:01 -0700
>
> > There was no public mail. I asked RH engineering for proposals for
> > changes to the POSIX spec and Alan replied.
>
> Please do not discuss such proposals only privately, especially when
> the ramifications affect the entire community.
>
> It is important the things get hashed out on a public forum where
> all networking developers can add their insight into the problem.
It was - about six years ago while netbeui/netbios merging was being
discussed. It got tagged then and finally ended up here.
^ permalink raw reply
* Re: incorrect cksum with tcp/udp on lo with 2.6.20/2.6.21/2.6.22
From: Krzysztof Oledzki @ 2007-09-23 21:18 UTC (permalink / raw)
To: Herbert Xu; +Cc: netdev
In-Reply-To: <E1IZJFo-0006ta-00@gondolin.me.apana.org.au>
[-- Attachment #1: Type: TEXT/PLAIN, Size: 656 bytes --]
On Sun, 23 Sep 2007, Herbert Xu wrote:
> Krzysztof Oledzki <olel@ans.pl> wrote:
>>
>> It seems that after some not very recent changes udp and tcp packes
>> carring data send by a loopback have incorrect cksum:
>
> This correct. The loopback interfaces has the no checksum flag
> set so we only provide a partial checksum on output (i.e., the
> pseudoheader without the payload).
>
> We even export this to user-space via a flag. So you should fix
> tcpdump to read this flag and ignore the checksum.
Thank you for the information. Is there any easy way to turn them on? I
need it for LVS.
Best regards,
Krzysztof Olędzki
^ permalink raw reply
* [ofa-general] Re: [PATCHES] TX batching
From: jamal @ 2007-09-23 21:20 UTC (permalink / raw)
To: Kok, Auke
Cc: randy.dunlap, Robert.Olsson, gaagaan, kumarkr,
peter.p.waskiewicz.jr, shemminger, johnpol, herbert, Jeff Garzik,
rdreier, mcarlson, general, sri, jagana, mchan, netdev, kaber,
tgraf, David Miller
In-Reply-To: <46F6C059.6000600@intel.com>
On Sun, 2007-23-09 at 12:36 -0700, Kok, Auke wrote:
> please be reminded that we're going to strip down e1000 and most of the features
> should go into e1000e, which has much less hardware workarounds. I'm still
> reluctant to putting in new stuff in e1000 - I really want to chop it down first ;)
sure - the question then is, will you take those changes if i use
e1000e? theres a few cleanups that have nothing to do with batching;
take a look at the modified e1000 on the git tree.
cheers,
jamal
^ permalink raw reply
* Re: incorrect cksum with tcp/udp on lo with 2.6.20/2.6.21/2.6.22
From: Herbert Xu @ 2007-09-24 1:30 UTC (permalink / raw)
To: Krzysztof Oledzki; +Cc: netdev
In-Reply-To: <Pine.LNX.4.64.0709232317001.24758@bizon.gios.gov.pl>
On Sun, Sep 23, 2007 at 11:18:58PM +0200, Krzysztof Oledzki wrote:
>
> Thank you for the information. Is there any easy way to turn them on? I
> need it for LVS.
Do you really need it? The packets should be checksummed at
the point where they physically leave the host.
Cheers,
--
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply
* Re: [PATCH: 2.6.13-15-SMP 3/3] network: concurrentlyrunsoftirqnetwork code on SMP
From: John Ye @ 2007-09-24 3:48 UTC (permalink / raw)
To: hadi; +Cc: David Miller, netdev, kuznet, pekkas, jmorris, kaber, iceburgue
In-Reply-To: <1190570864.4256.70.camel@localhost>
Dear Jamal,
Thanks, bothered you all.
I will look into the 2 issues. re-ordering and spinlock, and do extensive
test.
Once having result, no matter positive or negative, I will contact you.
The format will not be a mess any more.
John Ye
----- Original Message -----
From: "jamal" <hadi@cyberus.ca>
To: "john ye" <johny@asimco.com.cn>
Cc: "David Miller" <davem@davemloft.net>; <netdev@vger.kernel.org>;
<kuznet@ms2.inr.ac.ru>; <pekkas@netcore.fi>; <jmorris@namei.org>;
<kaber@coreworks.de>; <iceburgue@gmail.com>
Sent: Monday, September 24, 2007 2:07 AM
Subject: Re: [PATCH: 2.6.13-15-SMP 3/3] network:
concurrentlyrunsoftirqnetwork code on SMP
> John,
> It will NEVER be an acceptable solution as long as you have re-ordering.
> I will look at it - but i have to run out for now. In the meantime,
> I have indented it for you to be in proper kernel format so others can
> also look it. Attached.
>
> cheers,
> jamal
>
>
^ permalink raw reply
* Re: pktgen question
From: Ben Greear @ 2007-09-24 6:30 UTC (permalink / raw)
To: hadi; +Cc: Steve Wise, Evgeniy Polyakov, netdev, Robert Olsson
In-Reply-To: <1190571527.4256.78.camel@localhost>
jamal wrote:
> On Sun, 2007-23-09 at 12:55 -0500, Steve Wise wrote:
>
>
>> Its a hack that breaks cxgb3 because cxgb3 uses the skb->cb area for
>> each skb passed down. So cxgb3 is at fault then? IE a driver cannot
>> use the skb->cb field if the users count is > 1? Or maybe a driver can
>> _never_ use the cb field?
>>
>
> any layer can use the cb structure whichever way they wish. There are
> violations, e.g:
> the vlan code also uses the cb field to pass vlan details for hardware
> acceleration. How does pktgen affect it though, clone() will just copy
> the cb field and pktgen doesnt touch it.
> In retrospect, pktgen may have to use clone - ccing Robert Olsson.
>
Pktgen abuses the ref count, as far as I can tell. It works with most
ethernet drivers,
but that multi-pkt will also fail with things like vlans because the
skb->dev is changed
as it is transmitted (to the lower-level device).
I'd say just don't use the multi-pkt with pktgen on devices that can't
handle it.
Thanks,
Ben
--
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc http://www.candelatech.com
^ permalink raw reply
* [ofa-general] Re: [PATCHES] TX batching
From: Kok, Auke @ 2007-09-24 7:00 UTC (permalink / raw)
To: hadi
Cc: randy.dunlap, Robert.Olsson, gaagaan, kumarkr,
peter.p.waskiewicz.jr, shemminger, johnpol, herbert, Jeff Garzik,
rdreier, mcarlson, general, sri, jagana, mchan, Kok, Auke, netdev,
David Miller, tgraf, kaber
In-Reply-To: <1190582448.4240.2.camel@localhost>
jamal wrote:
> On Sun, 2007-23-09 at 12:36 -0700, Kok, Auke wrote:
>
>> please be reminded that we're going to strip down e1000 and most of the features
>> should go into e1000e, which has much less hardware workarounds. I'm still
>> reluctant to putting in new stuff in e1000 - I really want to chop it down first ;)
>
> sure - the question then is, will you take those changes if i use
> e1000e? theres a few cleanups that have nothing to do with batching;
> take a look at the modified e1000 on the git tree.
that's bad to begin with :) - please send those separately so I can fasttrack them
into e1000e and e1000 where applicable.
But yes, I'm very inclined to merge more features into e1000e than e1000. I intend
to put multiqueue support into e1000e, as *all* of the hardware that it will
support has multiple queues. Putting in any other performance feature like tx
batching would absolutely be interesting.
Auke
^ permalink raw reply
* [PATCH] fix mace_handle_misc_intrs compilation
From: Olaf Hering @ 2007-09-24 8:15 UTC (permalink / raw)
To: Andrew Morton, linuxppc-dev, netdev
Fix compilation after incomplete struct net_device changes.
Signed-off-by: Olaf Hering <olaf@aepfle.de>
---
drivers/net/mace.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
--- a/drivers/net/mace.c
+++ b/drivers/net/mace.c
@@ -633,7 +633,7 @@ static void mace_set_multicast(struct ne
spin_unlock_irqrestore(&mp->lock, flags);
}
-static void mace_handle_misc_intrs(struct mace_data *mp, int intr)
+static void mace_handle_misc_intrs(struct mace_data *mp, int intr, struct net_device *dev)
{
volatile struct mace __iomem *mb = mp->mace;
static int mace_babbles, mace_jabbers;
@@ -669,7 +669,7 @@ static irqreturn_t mace_interrupt(int ir
spin_lock_irqsave(&mp->lock, flags);
intr = in_8(&mb->ir); /* read interrupt register */
in_8(&mb->xmtrc); /* get retries */
- mace_handle_misc_intrs(mp, intr);
+ mace_handle_misc_intrs(mp, intr, dev);
i = mp->tx_empty;
while (in_8(&mb->pr) & XMTSV) {
@@ -682,7 +682,7 @@ static irqreturn_t mace_interrupt(int ir
*/
intr = in_8(&mb->ir);
if (intr != 0)
- mace_handle_misc_intrs(mp, intr);
+ mace_handle_misc_intrs(mp, intr, dev);
if (mp->tx_bad_runt) {
fs = in_8(&mb->xmtfs);
mp->tx_bad_runt = 0;
@@ -817,7 +817,7 @@ static void mace_tx_timeout(unsigned lon
goto out;
/* update various counters */
- mace_handle_misc_intrs(mp, in_8(&mb->ir));
+ mace_handle_misc_intrs(mp, in_8(&mb->ir), dev);
cp = mp->tx_cmds + NCMDS_TX * mp->tx_empty;
^ permalink raw reply
* Re: [PATCH] fix mace_handle_misc_intrs compilation
From: Andrew Morton @ 2007-09-24 8:22 UTC (permalink / raw)
To: Olaf Hering; +Cc: linuxppc-dev, netdev
In-Reply-To: <20070924081501.GA1797@aepfle.de>
On Mon, 24 Sep 2007 10:15:01 +0200 Olaf Hering <olaf@aepfle.de> wrote:
> Fix compilation after incomplete struct net_device changes.
yup, thanks, Kamalesh Babulal has already sent in an identical
patch.
^ permalink raw reply
* Re: change the way e1000 is handling short VLAN frames
From: Emil Micek @ 2007-09-24 8:40 UTC (permalink / raw)
To: netdev mailing list
Cc: auke-jan.h.kok@intel.com, Ben Greear, Chris Leech,
Francesco Fondelli, jamal, Jesse
In-Reply-To: <41b516cb0709211502v5a9931bfx267d163c51bd4958@mail.gmail.com>
Thanks for your replies.
We contacted Arris (manufacturer of our CMTS) about this issue with
links to relevant parts of specification about minimum size of VLAN
tagged frames and it seems they'll acknowledge the problem and fix it in
next firmware.
Meantime i tried different suggestions posted there (patch from Chris,
replacing ETH_ZLEN with VLAN_ETH_ZLEN in e1000_main.c and disabling HW
VLAN tagging in netdev->features) and combinations of them, but none of
it worked and 64B VLAN frames are still generated by our intel NIC.
I'll now consider this issue as closed on the e1000 and intel NIC side,
because there was no problem with them in the first place, and I'll
rather concentrate on resolving it on the CMTS side which doesn't act
according to specs.
Cheer
Emil.
^ permalink raw reply
* [PATCH] Clean up redundant PHY write line for ULi526x Ethernet driver
From: Zang Roy-r61911 @ 2007-09-24 8:57 UTC (permalink / raw)
To: jeff; +Cc: Andrew Morton, netdev
From: Roy Zang <tie-fei.zang@freescale.com>
Clean up redundant PHY write line for ULi526x Ethernet
Driver.
Signed-off-by: Roy Zang <tie-fei.zang@freescale.com>
---
drivers/net/tulip/uli526x.c | 1 -
1 files changed, 0 insertions(+), 1 deletions(-)
diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c
index ca2548e..53a8e65 100644
--- a/drivers/net/tulip/uli526x.c
+++ b/drivers/net/tulip/uli526x.c
@@ -1512,7 +1512,6 @@ static void uli526x_process_mode(struct uli526x_board_info *db)
case ULI526X_100MFD: phy_reg = 0x2100; break;
}
phy_write(db->ioaddr, db->phy_addr, 0, phy_reg, db->chip_id);
- phy_write(db->ioaddr, db->phy_addr, 0, phy_reg, db->chip_id);
}
}
}
--
1.5.2
^ permalink raw reply related
* [RFC PATCH 3/3] [TCP] MIB: Count FRTO's successfully detected spurious RTOs
From: Ilpo Järvinen @ 2007-09-24 9:04 UTC (permalink / raw)
To: David Miller; +Cc: netdev
In-Reply-To: <11906246484144-git-send-email-ilpo.jarvinen@helsinki.fi>
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@helsinki.fi>
---
include/linux/snmp.h | 1 +
net/ipv4/proc.c | 1 +
net/ipv4/tcp_input.c | 1 +
3 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/include/linux/snmp.h b/include/linux/snmp.h
index d8fd3ec..89f0c2b 100644
--- a/include/linux/snmp.h
+++ b/include/linux/snmp.h
@@ -213,6 +213,7 @@ enum
LINUX_MIB_TCPSACKDISCARD, /* TCPSACKDiscard */
LINUX_MIB_TCPDSACKIGNOREDOLD, /* TCPSACKIgnoredOld */
LINUX_MIB_TCPDSACKIGNOREDNOUNDO, /* TCPSACKIgnoredNoUndo */
+ LINUX_MIB_TCPSPURIOUSRTOS, /* TCPSpuriousRTOs */
__LINUX_MIB_MAX
};
diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c
index 2015148..9dee70e 100644
--- a/net/ipv4/proc.c
+++ b/net/ipv4/proc.c
@@ -245,6 +245,7 @@ static const struct snmp_mib snmp4_net_list[] = {
SNMP_MIB_ITEM("TCPSACKDiscard", LINUX_MIB_TCPSACKDISCARD),
SNMP_MIB_ITEM("TCPDSACKIgnoredOld", LINUX_MIB_TCPDSACKIGNOREDOLD),
SNMP_MIB_ITEM("TCPDSACKIgnoredNoUndo", LINUX_MIB_TCPDSACKIGNOREDNOUNDO),
+ SNMP_MIB_ITEM("TCPSpuriousRTOs", LINUX_MIB_TCPSPURIOUSRTOS),
SNMP_MIB_SENTINEL
};
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index ae06b94..259f517 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -2935,6 +2935,7 @@ static int tcp_process_frto(struct sock *sk, int flag)
}
tp->frto_counter = 0;
tp->undo_marker = 0;
+ NET_INC_STATS_BH(LINUX_MIB_TCPSPURIOUSRTOS);
}
return 0;
}
--
1.5.0.6
^ permalink raw reply related
* [RFC PATCH 2/3] [TCP]: Reordered ACK's (old) SACKs not included to discarded MIB
From: Ilpo Järvinen @ 2007-09-24 9:04 UTC (permalink / raw)
To: David Miller; +Cc: netdev
In-Reply-To: <11906246483657-git-send-email-ilpo.jarvinen@helsinki.fi>
In case of ACK reordering, the SACK block might be valid in it's
time but is already obsoleted since we've received another kind
of confirmation about arrival of the segments through snd_una
advancement of an earlier packet.
I didn't bother to build distinguishing of valid and invalid
SACK blocks but simply made reordered SACK blocks that are too
old always not counted regardless of their "real" validity which
could be determined by using the ack field of the reordered
packet (won't be significant IMHO).
DSACKs can very well be considered useful even in this situation,
so won't do any of this for them.
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@helsinki.fi>
---
net/ipv4/tcp_input.c | 7 ++++++-
1 files changed, 6 insertions(+), 1 deletions(-)
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 532288b..ae06b94 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -1250,8 +1250,13 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
NET_INC_STATS_BH(LINUX_MIB_TCPDSACKIGNOREDNOUNDO);
else
NET_INC_STATS_BH(LINUX_MIB_TCPDSACKIGNOREDOLD);
- } else
+ } else {
+ /* Don't count olds caused by ACK reordering */
+ if ((TCP_SKB_CB(ack_skb)->ack_seq != tp->snd_una) &&
+ !after(end_seq, tp->snd_una))
+ continue;
NET_INC_STATS_BH(LINUX_MIB_TCPSACKDISCARD);
+ }
continue;
}
--
1.5.0.6
^ permalink raw reply related
* [PATCH net-2.6.24 0/3]: TCP tweaks
From: Ilpo Järvinen @ 2007-09-24 9:04 UTC (permalink / raw)
To: David Miller; +Cc: netdev
Hi Dave,
Here are some minor tweaks to recent net-2.6.24 changes, more or
less mandatory. The first one is the most important one because
if the not-supposed-to-happen case occurs, TCP would be left to
an inconsistent state. As regards the second, I'm fine with
either way. The third one's MIB for FRTO is sort of nice to have
but definately not mandatory. I'm leaving decision about those
two to you if you're fine with them feel free to apply :-).
--
i.
^ permalink raw reply
* [PATCH 1/3] [TCP]: Re-place highest_sack check to a more robust position
From: Ilpo Järvinen @ 2007-09-24 9:04 UTC (permalink / raw)
To: David Miller; +Cc: netdev
In-Reply-To: <11906246483472-git-send-email-ilpo.jarvinen@helsinki.fi>
I previously added checking to position that is rather poor as
state has already been adjusted quite a bit. Re-placing it above
all state changes should be more robust though the return should
never ever get executed regardless of its place :-).
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@helsinki.fi>
---
net/ipv4/tcp_output.c | 8 ++++----
1 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index cbb83ac..94c8011 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -1718,6 +1718,10 @@ static void tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *skb, int m
BUG_ON(tcp_skb_pcount(skb) != 1 ||
tcp_skb_pcount(next_skb) != 1);
+ if (WARN_ON(tp->sacked_out &&
+ (TCP_SKB_CB(next_skb)->seq == tp->highest_sack)))
+ return;
+
/* Ok. We will be able to collapse the packet. */
tcp_unlink_write_queue(next_skb, sk);
@@ -1734,10 +1738,6 @@ static void tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *skb, int m
/* Update sequence range on original skb. */
TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(next_skb)->end_seq;
- if (WARN_ON(tp->sacked_out &&
- (TCP_SKB_CB(next_skb)->seq == tp->highest_sack)))
- return;
-
/* Merge over control information. */
flags |= TCP_SKB_CB(next_skb)->flags; /* This moves PSH/FIN etc. over */
TCP_SKB_CB(skb)->flags = flags;
--
1.5.0.6
^ permalink raw reply related
* Re: incorrect cksum with tcp/udp on lo with 2.6.20/2.6.21/2.6.22
From: Krzysztof Oledzki @ 2007-09-24 9:44 UTC (permalink / raw)
To: Herbert Xu; +Cc: netdev
In-Reply-To: <20070924013005.GB22054@gondor.apana.org.au>
[-- Attachment #1: Type: TEXT/PLAIN, Size: 728 bytes --]
On Mon, 24 Sep 2007, Herbert Xu wrote:
> On Sun, Sep 23, 2007 at 11:18:58PM +0200, Krzysztof Oledzki wrote:
>>
>> Thank you for the information. Is there any easy way to turn them on? I
>> need it for LVS.
>
> Do you really need it?
Yes. I would like to use a LVS redirector as both a client and a director:
http://www.austintek.com/LVS/LVS-HOWTO/HOWTO/LVS-HOWTO.LVS-DR.html#director_as_client_in_LVS-DR
> The packets should be checksummed at the point where they physically
> leave the host.
So, with DR mode, packet goes by the lo device (with bad checksum) and
then get redirected outside. Unfortunately, when it leaves host it has bad
checksum, too. :(
Best regards,
Krzysztof Olędzki
^ permalink raw reply
* [PATCH 3/5] [TCP]: Convert highest_sack to sk_buff to allow direct access
From: Ilpo Järvinen @ 2007-09-24 10:28 UTC (permalink / raw)
To: David Miller, Stephen Hemminger, SANGTAE HA, Tom Quetchenbach,
Baruch Even <bar
Cc: netdev, Ilpo Järvinen
In-Reply-To: <11906297271155-git-send-email-ilpo.jarvinen@helsinki.fi>
From: =?ISO-8859-1?q?Ilpo_J=E4rvinen?= <ilpo.jarvinen@helsinki.fi>
It is going to replace the sack fastpath hint quite soon... :-)
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@helsinki.fi>
---
include/linux/tcp.h | 6 ++++--
include/net/tcp.h | 13 +++++++++++++
net/ipv4/tcp_input.c | 12 ++++++------
net/ipv4/tcp_output.c | 19 ++++++++++---------
4 files changed, 33 insertions(+), 17 deletions(-)
diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index f8cf090..1d6be2a 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -332,8 +332,10 @@ struct tcp_sock {
struct tcp_sack_block_wire recv_sack_cache[4];
- u32 highest_sack; /* Start seq of globally highest revd SACK
- * (validity guaranteed only if sacked_out > 0) */
+ struct sk_buff *highest_sack; /* highest skb with SACK received
+ * (validity guaranteed only if
+ * sacked_out > 0)
+ */
/* from STCP, retrans queue hinting */
struct sk_buff* lost_skb_hint;
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 991ccdc..8bc64b7 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -1308,6 +1308,19 @@ static inline int tcp_write_queue_empty(struct sock *sk)
return skb_queue_empty(&sk->sk_write_queue);
}
+/* Start sequence of the highest skb with SACKed bit, valid only if
+ * sacked > 0 or when the caller has ensured validity by itself.
+ */
+static inline u32 tcp_highest_sack_seq(struct sock *sk)
+{
+ struct tcp_sock *tp = tcp_sk(sk);
+
+ if (WARN_ON(!tp->sacked_out &&
+ tp->highest_sack != tcp_write_queue_head(sk)))
+ return tp->snd_una;
+ return TCP_SKB_CB(tp->highest_sack)->seq;
+}
+
/* /proc */
enum tcp_seq_states {
TCP_SEQ_STATE_LISTENING,
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 76e9c9b..85dd4b0 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -1143,10 +1143,11 @@ static int tcp_check_dsack(struct tcp_sock *tp, struct sk_buff *ack_skb,
return dup_sack;
}
-static void tcp_sacktag_one(struct sk_buff *skb, struct tcp_sock *tp,
+static void tcp_sacktag_one(struct sk_buff *skb, struct sock *sk,
struct tcp_sacktag_state *state, int in_sack,
int dup_sack, int fack_count, u32 end_seq)
{
+ struct tcp_sock *tp = tcp_sk(sk);
u8 sacked = TCP_SKB_CB(skb)->sacked;
/* Account D-SACK for retransmitted packet. */
@@ -1231,9 +1232,8 @@ static void tcp_sacktag_one(struct sk_buff *skb, struct tcp_sock *tp,
if (fack_count > tp->fackets_out)
tp->fackets_out = fack_count;
- if (after(TCP_SKB_CB(skb)->seq,
- tp->highest_sack))
- tp->highest_sack = TCP_SKB_CB(skb)->seq;
+ if (after(TCP_SKB_CB(skb)->seq, tcp_highest_sack_seq(sk)))
+ tp->highest_sack = skb;
} else {
if (dup_sack && (sacked&TCPCB_RETRANS))
state->reord = min(fack_count, state->reord);
@@ -1271,7 +1271,7 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
if (!tp->sacked_out) {
tp->fackets_out = 0;
- tp->highest_sack = tp->snd_una;
+ tp->highest_sack = tcp_write_queue_head(sk);
}
found_dup_sack = tcp_check_dsack(tp, ack_skb, sp, num_sacks, prior_snd_una);
@@ -1424,7 +1424,7 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
fack_count += pcount;
- tcp_sacktag_one(skb, tp, &state, in_sack,
+ tcp_sacktag_one(skb, sk, &state, in_sack,
dup_sack, fack_count, end_seq);
}
}
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 94c8011..fd51692 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -657,13 +657,15 @@ static void tcp_set_skb_tso_segs(struct sock *sk, struct sk_buff *skb, unsigned
* tweak SACK fastpath hint too as it would overwrite all changes unless
* hint is also changed.
*/
-static void tcp_adjust_fackets_out(struct tcp_sock *tp, struct sk_buff *skb,
+static void tcp_adjust_fackets_out(struct sock *sk, struct sk_buff *skb,
int decr)
{
+ struct tcp_sock *tp = tcp_sk(sk);
+
if (!tp->sacked_out)
return;
- if (!before(tp->highest_sack, TCP_SKB_CB(skb)->seq))
+ if (!before(tcp_highest_sack_seq(sk), TCP_SKB_CB(skb)->seq))
tp->fackets_out -= decr;
/* cnt_hint is "off-by-one" compared with fackets_out (see sacktag) */
@@ -712,8 +714,8 @@ int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len, unsigned int mss
TCP_SKB_CB(buff)->end_seq = TCP_SKB_CB(skb)->end_seq;
TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(buff)->seq;
- if (tp->sacked_out && (TCP_SKB_CB(skb)->seq == tp->highest_sack))
- tp->highest_sack = TCP_SKB_CB(buff)->seq;
+ if (tp->sacked_out && (skb == tp->highest_sack))
+ tp->highest_sack = buff;
/* PSH and FIN should only be set in the second packet. */
flags = TCP_SKB_CB(skb)->flags;
@@ -771,7 +773,7 @@ int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len, unsigned int mss
tcp_dec_pcount_approx_int(&tp->sacked_out, diff);
tcp_verify_left_out(tp);
}
- tcp_adjust_fackets_out(tp, skb, diff);
+ tcp_adjust_fackets_out(sk, skb, diff);
}
/* Link BUFF into the send queue. */
@@ -1718,8 +1720,7 @@ static void tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *skb, int m
BUG_ON(tcp_skb_pcount(skb) != 1 ||
tcp_skb_pcount(next_skb) != 1);
- if (WARN_ON(tp->sacked_out &&
- (TCP_SKB_CB(next_skb)->seq == tp->highest_sack)))
+ if (WARN_ON(tp->sacked_out && (next_skb == tp->highest_sack)))
return;
/* Ok. We will be able to collapse the packet. */
@@ -1754,7 +1755,7 @@ static void tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *skb, int m
if (tcp_is_reno(tp) && tp->sacked_out)
tcp_dec_pcount_approx(&tp->sacked_out, next_skb);
- tcp_adjust_fackets_out(tp, skb, tcp_skb_pcount(next_skb));
+ tcp_adjust_fackets_out(sk, skb, tcp_skb_pcount(next_skb));
tp->packets_out -= tcp_skb_pcount(next_skb);
/* changed transmit queue under us so clear hints */
@@ -2031,7 +2032,7 @@ void tcp_xmit_retransmit_queue(struct sock *sk)
break;
tp->forward_skb_hint = skb;
- if (after(TCP_SKB_CB(skb)->seq, tp->highest_sack))
+ if (after(TCP_SKB_CB(skb)->seq, tcp_highest_sack_seq(sk)))
break;
if (tcp_packets_in_flight(tp) >= tp->snd_cwnd)
--
1.5.0.6
^ permalink raw reply related
* [RFC PATCH net-2.6.24 0/5]: TCP sacktag cache usage recoded
From: Ilpo Järvinen @ 2007-09-24 10:28 UTC (permalink / raw)
To: David Miller, Stephen Hemminger, SANGTAE HA, Tom Quetchenbach,
Baruch Even <bar
Cc: netdev
Hi all,
After couple of wrong-wayed before/after()s and one infinite
loopy version, here's the current trial version of a sacktag
cache usage recode....
Two first patches come from tcp-2.6 (rebased and rotated).
This series apply cleanly only on top of the other three patch
series I posted earlier today. The last debug patch provides
some statistics for those interested enough.
Dave, please DO NOT apply! ...Some thoughts could be nice
though :-).
It should improve processing of such likely events as cumulative
ACKs and new forward holed SACK considerably because full walk
is not necessary anymore (old code could have been tweaked to
cover them but it's better to drop each special case handling
altogether and do a generic solution. Redundancy of fastpath
hints and highest_sack stuff is also addressed, however, it
might have slight effect as the hint could point to something
less than highest_sack occassionally, whether that's significant
remains to see... In all cases except hint below highest_sack,
the new solution should perform at least as well as the old code
(with a bit larger constant though, no additional cache misses
though) because the SACK blocks old code choose not to process
should all fall to LINUX_MIB_TCP_FULLSKIP category.
It's possible to improve it easily with RB-tree stuff though
this version is based on code using linked lists. I'm not yet
too sure that I got everything 100% correct as I "tweak"
start/end_seqs and exit skb loops a way that is prone to
off-by-one errors, could miss skb here and there. I'll probably
also recode dsack handling too to avoid recursion.
Stephen, Sangtae, others? experiencing those unexpected RTOs
during recovery of large windowed TCP, could you please give it
a try if it helps any...
--
i.
ps. Our net-2.6.24 (and mainline?) DSACK processing code could
be broken btw. DSACK in the middle of other SACK block during
in-order walk seems to not be processed at all as the earlier
(sorted) block caused skb to advance past it already? (Just
occurred to me, I'll see what I can do to that if I've enough
time).
^ permalink raw reply
* [PATCH 2/5] [TCP]: Create tcp_sacktag_one().
From: Ilpo Järvinen @ 2007-09-24 10:28 UTC (permalink / raw)
To: David Miller, Stephen Hemminger, SANGTAE HA, Tom Quetchenbach,
Baruch Even <bar
Cc: netdev, David S. Miller
In-Reply-To: <11906297272364-git-send-email-ilpo.jarvinen@helsinki.fi>
From: David S. Miller <davem@sunset.davemloft.net>
Worker function that implements the main logic of
the inner-most loop of tcp_sacktag_write_queue().
Signed-off-by: David S. Miller <davem@davemloft.net>
Acked-by: Ilpo Järvinen <ilpo.jarvinen@helsinki.fi>
---
net/ipv4/tcp_input.c | 213 ++++++++++++++++++++++++++------------------------
1 files changed, 110 insertions(+), 103 deletions(-)
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 04ff465..76e9c9b 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -1143,6 +1143,114 @@ static int tcp_check_dsack(struct tcp_sock *tp, struct sk_buff *ack_skb,
return dup_sack;
}
+static void tcp_sacktag_one(struct sk_buff *skb, struct tcp_sock *tp,
+ struct tcp_sacktag_state *state, int in_sack,
+ int dup_sack, int fack_count, u32 end_seq)
+{
+ u8 sacked = TCP_SKB_CB(skb)->sacked;
+
+ /* Account D-SACK for retransmitted packet. */
+ if ((dup_sack && in_sack) &&
+ (sacked & TCPCB_RETRANS) &&
+ after(TCP_SKB_CB(skb)->end_seq, tp->undo_marker))
+ tp->undo_retrans--;
+
+ /* The frame is ACKed. */
+ if (!after(TCP_SKB_CB(skb)->end_seq, tp->snd_una)) {
+ if (sacked & TCPCB_RETRANS) {
+ if ((dup_sack && in_sack) &&
+ (sacked & TCPCB_SACKED_ACKED))
+ state->reord = min(fack_count, state->reord);
+ } else {
+ /* If it was in a hole, we detected reordering. */
+ if (fack_count < state->prior_fackets &&
+ !(sacked & TCPCB_SACKED_ACKED))
+ state->reord = min(fack_count, state->reord);
+ }
+
+ /* Nothing to do; acked frame is about to be dropped. */
+ return;
+ }
+
+ if ((sacked & TCPCB_SACKED_RETRANS) &&
+ after(end_seq, TCP_SKB_CB(skb)->ack_seq) &&
+ (!state->lost_retrans || after(end_seq, state->lost_retrans)))
+ state->lost_retrans = end_seq;
+
+ if (!in_sack)
+ return;
+
+ if (!(sacked & TCPCB_SACKED_ACKED)) {
+ if (sacked & TCPCB_SACKED_RETRANS) {
+ /* If the segment is not tagged as lost,
+ * we do not clear RETRANS, believing
+ * that retransmission is still in flight.
+ */
+ if (sacked & TCPCB_LOST) {
+ TCP_SKB_CB(skb)->sacked &=
+ ~(TCPCB_LOST|TCPCB_SACKED_RETRANS);
+ tp->lost_out -= tcp_skb_pcount(skb);
+ tp->retrans_out -= tcp_skb_pcount(skb);
+
+ /* clear lost hint */
+ tp->retransmit_skb_hint = NULL;
+ }
+ } else {
+ /* New sack for not retransmitted frame,
+ * which was in hole. It is reordering.
+ */
+ if (!(sacked & TCPCB_RETRANS) &&
+ fack_count < state->prior_fackets)
+ state->reord = min(fack_count, state->reord);
+
+ if (sacked & TCPCB_LOST) {
+ TCP_SKB_CB(skb)->sacked &= ~TCPCB_LOST;
+ tp->lost_out -= tcp_skb_pcount(skb);
+
+ /* clear lost hint */
+ tp->retransmit_skb_hint = NULL;
+ }
+ /* SACK enhanced F-RTO detection.
+ * Set flag if and only if non-rexmitted
+ * segments below frto_highmark are
+ * SACKed (RFC4138; Appendix B).
+ * Clearing correct due to in-order walk
+ */
+ if (after(end_seq, tp->frto_highmark)) {
+ state->flag &= ~FLAG_ONLY_ORIG_SACKED;
+ } else {
+ if (!(sacked & TCPCB_RETRANS))
+ state->flag |= FLAG_ONLY_ORIG_SACKED;
+ }
+ }
+
+ TCP_SKB_CB(skb)->sacked |= TCPCB_SACKED_ACKED;
+ state->flag |= FLAG_DATA_SACKED;
+ tp->sacked_out += tcp_skb_pcount(skb);
+
+ if (fack_count > tp->fackets_out)
+ tp->fackets_out = fack_count;
+
+ if (after(TCP_SKB_CB(skb)->seq,
+ tp->highest_sack))
+ tp->highest_sack = TCP_SKB_CB(skb)->seq;
+ } else {
+ if (dup_sack && (sacked&TCPCB_RETRANS))
+ state->reord = min(fack_count, state->reord);
+ }
+
+ /* D-SACK. We can detect redundant retransmission
+ * in S|R and plain R frames and clear it.
+ * undo_retrans is decreased above, L|R frames
+ * are accounted above as well.
+ */
+ if (dup_sack && (TCP_SKB_CB(skb)->sacked&TCPCB_SACKED_RETRANS)) {
+ TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_RETRANS;
+ tp->retrans_out -= tcp_skb_pcount(skb);
+ tp->retransmit_skb_hint = NULL;
+ }
+}
+
static int
tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_una)
{
@@ -1274,7 +1382,6 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
tcp_for_write_queue_from(skb, sk) {
int in_sack, pcount;
- u8 sacked;
if (skb == tcp_send_head(sk))
break;
@@ -1317,108 +1424,8 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
fack_count += pcount;
- sacked = TCP_SKB_CB(skb)->sacked;
-
- /* Account D-SACK for retransmitted packet. */
- if ((dup_sack && in_sack) &&
- (sacked & TCPCB_RETRANS) &&
- after(TCP_SKB_CB(skb)->end_seq, tp->undo_marker))
- tp->undo_retrans--;
-
- /* The frame is ACKed. */
- if (!after(TCP_SKB_CB(skb)->end_seq, tp->snd_una)) {
- if (sacked&TCPCB_RETRANS) {
- if ((dup_sack && in_sack) &&
- (sacked&TCPCB_SACKED_ACKED))
- state.reord = min(fack_count, state.reord);
- } else {
- /* If it was in a hole, we detected reordering. */
- if (fack_count < state.prior_fackets &&
- !(sacked&TCPCB_SACKED_ACKED))
- state.reord = min(fack_count, state.reord);
- }
-
- /* Nothing to do; acked frame is about to be dropped. */
- continue;
- }
-
- if ((sacked&TCPCB_SACKED_RETRANS) &&
- after(end_seq, TCP_SKB_CB(skb)->ack_seq) &&
- (!state.lost_retrans || after(end_seq, state.lost_retrans)))
- state.lost_retrans = end_seq;
-
- if (!in_sack)
- continue;
-
- if (!(sacked&TCPCB_SACKED_ACKED)) {
- if (sacked & TCPCB_SACKED_RETRANS) {
- /* If the segment is not tagged as lost,
- * we do not clear RETRANS, believing
- * that retransmission is still in flight.
- */
- if (sacked & TCPCB_LOST) {
- TCP_SKB_CB(skb)->sacked &= ~(TCPCB_LOST|TCPCB_SACKED_RETRANS);
- tp->lost_out -= tcp_skb_pcount(skb);
- tp->retrans_out -= tcp_skb_pcount(skb);
-
- /* clear lost hint */
- tp->retransmit_skb_hint = NULL;
- }
- } else {
- /* New sack for not retransmitted frame,
- * which was in hole. It is reordering.
- */
- if (!(sacked & TCPCB_RETRANS) &&
- fack_count < state.prior_fackets)
- state.reord = min(fack_count, state.reord);
-
- if (sacked & TCPCB_LOST) {
- TCP_SKB_CB(skb)->sacked &= ~TCPCB_LOST;
- tp->lost_out -= tcp_skb_pcount(skb);
-
- /* clear lost hint */
- tp->retransmit_skb_hint = NULL;
- }
- /* SACK enhanced F-RTO detection.
- * Set flag if and only if non-rexmitted
- * segments below frto_highmark are
- * SACKed (RFC4138; Appendix B).
- * Clearing correct due to in-order walk
- */
- if (after(end_seq, tp->frto_highmark)) {
- state.flag &= ~FLAG_ONLY_ORIG_SACKED;
- } else {
- if (!(sacked & TCPCB_RETRANS))
- state.flag |= FLAG_ONLY_ORIG_SACKED;
- }
- }
-
- TCP_SKB_CB(skb)->sacked |= TCPCB_SACKED_ACKED;
- state.flag |= FLAG_DATA_SACKED;
- tp->sacked_out += tcp_skb_pcount(skb);
-
- if (fack_count > tp->fackets_out)
- tp->fackets_out = fack_count;
-
- if (after(TCP_SKB_CB(skb)->seq,
- tp->highest_sack))
- tp->highest_sack = TCP_SKB_CB(skb)->seq;
- } else {
- if (dup_sack && (sacked&TCPCB_RETRANS))
- state.reord = min(fack_count, state.reord);
- }
-
- /* D-SACK. We can detect redundant retransmission
- * in S|R and plain R frames and clear it.
- * undo_retrans is decreased above, L|R frames
- * are accounted above as well.
- */
- if (dup_sack &&
- (TCP_SKB_CB(skb)->sacked&TCPCB_SACKED_RETRANS)) {
- TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_RETRANS;
- tp->retrans_out -= tcp_skb_pcount(skb);
- tp->retransmit_skb_hint = NULL;
- }
+ tcp_sacktag_one(skb, tp, &state, in_sack,
+ dup_sack, fack_count, end_seq);
}
}
--
1.5.0.6
^ permalink raw reply related
* [PATCH 1/5] [TCP]: Create tcp_sacktag_state.
From: Ilpo Järvinen @ 2007-09-24 10:28 UTC (permalink / raw)
To: David Miller, Stephen Hemminger, SANGTAE HA, Tom Quetchenbach,
Baruch Even <bar
Cc: netdev, David S. Miller
In-Reply-To: <11906297271684-git-send-email-ilpo.jarvinen@helsinki.fi>
From: David S. Miller <davem@davemloft.net>
It is difficult to break out the inner-logic of
tcp_sacktag_write_queue() into worker functions because
so many local variables get updated in-place.
Start to overcome this by creating a structure block
of state variables that can be passed around into
worker routines.
[I made minor tweaks due to rebase/reordering of stuff
in tcp-2.6 tree, and dropped found_dup_sack & dup_sack
from state -ij]
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@helsinki.fi>
---
net/ipv4/tcp_input.c | 89 ++++++++++++++++++++++++++-----------------------
1 files changed, 47 insertions(+), 42 deletions(-)
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 259f517..04ff465 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -1102,6 +1102,13 @@ static int tcp_is_sackblock_valid(struct tcp_sock *tp, int is_dsack,
return !before(start_seq, end_seq - tp->max_window);
}
+struct tcp_sacktag_state {
+ unsigned int flag;
+ int reord;
+ int prior_fackets;
+ u32 lost_retrans;
+ int first_sack_index;
+};
static int tcp_check_dsack(struct tcp_sock *tp, struct sk_buff *ack_skb,
struct tcp_sack_block_wire *sp, int num_sacks,
@@ -1146,25 +1153,22 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
struct tcp_sack_block_wire *sp = (struct tcp_sack_block_wire *)(ptr+2);
struct sk_buff *cached_skb;
int num_sacks = (ptr[1] - TCPOLEN_SACK_BASE)>>3;
- int reord = tp->packets_out;
- int prior_fackets;
- u32 lost_retrans = 0;
- int flag = 0;
- int found_dup_sack = 0;
+ struct tcp_sacktag_state state;
+ int found_dup_sack;
int cached_fack_count;
int i;
- int first_sack_index;
+ int force_one_sack;
+
+ state.flag = 0;
if (!tp->sacked_out) {
tp->fackets_out = 0;
tp->highest_sack = tp->snd_una;
}
- prior_fackets = tp->fackets_out;
- found_dup_sack = tcp_check_dsack(tp, ack_skb, sp,
- num_sacks, prior_snd_una);
+ found_dup_sack = tcp_check_dsack(tp, ack_skb, sp, num_sacks, prior_snd_una);
if (found_dup_sack)
- flag |= FLAG_DSACKING_ACK;
+ state.flag |= FLAG_DSACKING_ACK;
/* Eliminate too old ACKs, but take into
* account more or less fresh ones, they can
@@ -1177,18 +1181,18 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
* if the only SACK change is the increase of the end_seq of
* the first block then only apply that SACK block
* and use retrans queue hinting otherwise slowpath */
- flag = 1;
+ force_one_sack = 1;
for (i = 0; i < num_sacks; i++) {
__be32 start_seq = sp[i].start_seq;
__be32 end_seq = sp[i].end_seq;
if (i == 0) {
if (tp->recv_sack_cache[i].start_seq != start_seq)
- flag = 0;
+ force_one_sack = 0;
} else {
if ((tp->recv_sack_cache[i].start_seq != start_seq) ||
(tp->recv_sack_cache[i].end_seq != end_seq))
- flag = 0;
+ force_one_sack = 0;
}
tp->recv_sack_cache[i].start_seq = start_seq;
tp->recv_sack_cache[i].end_seq = end_seq;
@@ -1199,8 +1203,8 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
tp->recv_sack_cache[i].end_seq = 0;
}
- first_sack_index = 0;
- if (flag)
+ state.first_sack_index = 0;
+ if (force_one_sack)
num_sacks = 1;
else {
int j;
@@ -1218,17 +1222,14 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
sp[j+1] = tmp;
/* Track where the first SACK block goes to */
- if (j == first_sack_index)
- first_sack_index = j+1;
+ if (j == state.first_sack_index)
+ state.first_sack_index = j+1;
}
}
}
}
- /* clear flag as used for different purpose in following code */
- flag = 0;
-
/* Use SACK fastpath hint if valid */
cached_skb = tp->fastpath_skb_hint;
cached_fack_count = tp->fastpath_cnt_hint;
@@ -1237,12 +1238,16 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
cached_fack_count = 0;
}
+ state.reord = tp->packets_out;
+ state.prior_fackets = tp->fackets_out;
+ state.lost_retrans = 0;
+
for (i=0; i<num_sacks; i++, sp++) {
struct sk_buff *skb;
__u32 start_seq = ntohl(sp->start_seq);
__u32 end_seq = ntohl(sp->end_seq);
int fack_count;
- int dup_sack = (found_dup_sack && (i == first_sack_index));
+ int dup_sack = (found_dup_sack && (i == state.first_sack_index));
if (!tcp_is_sackblock_valid(tp, dup_sack, start_seq, end_seq)) {
if (dup_sack) {
@@ -1265,7 +1270,7 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
/* Event "B" in the comment above. */
if (after(end_seq, tp->high_seq))
- flag |= FLAG_DATA_LOST;
+ state.flag |= FLAG_DATA_LOST;
tcp_for_write_queue_from(skb, sk) {
int in_sack, pcount;
@@ -1276,7 +1281,7 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
cached_skb = skb;
cached_fack_count = fack_count;
- if (i == first_sack_index) {
+ if (i == state.first_sack_index) {
tp->fastpath_skb_hint = skb;
tp->fastpath_cnt_hint = fack_count;
}
@@ -1325,12 +1330,12 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
if (sacked&TCPCB_RETRANS) {
if ((dup_sack && in_sack) &&
(sacked&TCPCB_SACKED_ACKED))
- reord = min(fack_count, reord);
+ state.reord = min(fack_count, state.reord);
} else {
/* If it was in a hole, we detected reordering. */
- if (fack_count < prior_fackets &&
+ if (fack_count < state.prior_fackets &&
!(sacked&TCPCB_SACKED_ACKED))
- reord = min(fack_count, reord);
+ state.reord = min(fack_count, state.reord);
}
/* Nothing to do; acked frame is about to be dropped. */
@@ -1339,8 +1344,8 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
if ((sacked&TCPCB_SACKED_RETRANS) &&
after(end_seq, TCP_SKB_CB(skb)->ack_seq) &&
- (!lost_retrans || after(end_seq, lost_retrans)))
- lost_retrans = end_seq;
+ (!state.lost_retrans || after(end_seq, state.lost_retrans)))
+ state.lost_retrans = end_seq;
if (!in_sack)
continue;
@@ -1364,8 +1369,8 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
* which was in hole. It is reordering.
*/
if (!(sacked & TCPCB_RETRANS) &&
- fack_count < prior_fackets)
- reord = min(fack_count, reord);
+ fack_count < state.prior_fackets)
+ state.reord = min(fack_count, state.reord);
if (sacked & TCPCB_LOST) {
TCP_SKB_CB(skb)->sacked &= ~TCPCB_LOST;
@@ -1381,15 +1386,15 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
* Clearing correct due to in-order walk
*/
if (after(end_seq, tp->frto_highmark)) {
- flag &= ~FLAG_ONLY_ORIG_SACKED;
+ state.flag &= ~FLAG_ONLY_ORIG_SACKED;
} else {
if (!(sacked & TCPCB_RETRANS))
- flag |= FLAG_ONLY_ORIG_SACKED;
+ state.flag |= FLAG_ONLY_ORIG_SACKED;
}
}
TCP_SKB_CB(skb)->sacked |= TCPCB_SACKED_ACKED;
- flag |= FLAG_DATA_SACKED;
+ state.flag |= FLAG_DATA_SACKED;
tp->sacked_out += tcp_skb_pcount(skb);
if (fack_count > tp->fackets_out)
@@ -1400,7 +1405,7 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
tp->highest_sack = TCP_SKB_CB(skb)->seq;
} else {
if (dup_sack && (sacked&TCPCB_RETRANS))
- reord = min(fack_count, reord);
+ state.reord = min(fack_count, state.reord);
}
/* D-SACK. We can detect redundant retransmission
@@ -1423,20 +1428,20 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
* we have to account for reordering! Ugly,
* but should help.
*/
- if (lost_retrans && icsk->icsk_ca_state == TCP_CA_Recovery) {
+ if (state.lost_retrans && icsk->icsk_ca_state == TCP_CA_Recovery) {
struct sk_buff *skb;
tcp_for_write_queue(skb, sk) {
if (skb == tcp_send_head(sk))
break;
- if (after(TCP_SKB_CB(skb)->seq, lost_retrans))
+ if (after(TCP_SKB_CB(skb)->seq, state.lost_retrans))
break;
if (!after(TCP_SKB_CB(skb)->end_seq, tp->snd_una))
continue;
if ((TCP_SKB_CB(skb)->sacked&TCPCB_SACKED_RETRANS) &&
- after(lost_retrans, TCP_SKB_CB(skb)->ack_seq) &&
+ after(state.lost_retrans, TCP_SKB_CB(skb)->ack_seq) &&
(tcp_is_fack(tp) ||
- !before(lost_retrans,
+ !before(state.lost_retrans,
TCP_SKB_CB(skb)->ack_seq + tp->reordering *
tp->mss_cache))) {
TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_RETRANS;
@@ -1448,7 +1453,7 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
if (!(TCP_SKB_CB(skb)->sacked&(TCPCB_LOST|TCPCB_SACKED_ACKED))) {
tp->lost_out += tcp_skb_pcount(skb);
TCP_SKB_CB(skb)->sacked |= TCPCB_LOST;
- flag |= FLAG_DATA_SACKED;
+ state.flag |= FLAG_DATA_SACKED;
NET_INC_STATS_BH(LINUX_MIB_TCPLOSTRETRANSMIT);
}
}
@@ -1457,9 +1462,9 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
tcp_verify_left_out(tp);
- if ((reord < tp->fackets_out) && icsk->icsk_ca_state != TCP_CA_Loss &&
+ if ((state.reord < tp->fackets_out) && icsk->icsk_ca_state != TCP_CA_Loss &&
(!tp->frto_highmark || after(tp->snd_una, tp->frto_highmark)))
- tcp_update_reordering(sk, ((tp->fackets_out + 1) - reord), 0);
+ tcp_update_reordering(sk, ((tp->fackets_out + 1) - state.reord), 0);
#if FASTRETRANS_DEBUG > 0
BUG_TRAP((int)tp->sacked_out >= 0);
@@ -1467,7 +1472,7 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
BUG_TRAP((int)tp->retrans_out >= 0);
BUG_TRAP((int)tcp_packets_in_flight(tp) >= 0);
#endif
- return flag;
+ return state.flag;
}
/* F-RTO can only be used if TCP has never retransmitted anything other than
--
1.5.0.6
^ permalink raw reply related
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