Commit c5b8ed35 authored by Chas Williams's avatar Chas Williams Committed by Hideaki Yoshifuji

[ATM]: empty tx queue in lec when flush complete

the lane spec says the following about path switching:

10.1.2.7 Transmitting Held Frames

Once the LE_FLUSH_RESPONSE is received, the LE Client MUST
transmit any held  data frames on the new data path before
transmitting any further frames on the new path.

10.1.2.8 Switching Over Paths Without Flush

Regardless of the provisions of the rest of Section 10.1, when
switching from the old path to a new path, if an LE Client has
not transmitted a data frame to a particular LAN Destination via
the old path for a period of time greater than or equal to the
C22 Path Switching Delay, then it MAY start using the new path
without employing the Flush protocol.

the lane client in linux-atm does do this but it doesnt send the
held frames until a frame is transmitted on the vcc after the flush
has completed.  often this doesnt happen until you get an ip retransmit.
the following patch sends the held frames after the flush completes
(or the switching delay expires)
parent 3def5542
...@@ -198,6 +198,23 @@ lec_open(struct net_device *dev) ...@@ -198,6 +198,23 @@ lec_open(struct net_device *dev)
return 0; return 0;
} }
static __inline__ void
lec_send(struct atm_vcc *vcc, struct sk_buff *skb, struct lec_priv *priv)
{
if (atm_may_send(vcc, skb->len)) {
atomic_add(skb->truesize, &vcc->tx_inuse);
ATM_SKB(skb)->vcc = vcc;
ATM_SKB(skb)->iovcnt = 0;
ATM_SKB(skb)->atm_options = vcc->atm_options;
priv->stats.tx_packets++;
priv->stats.tx_bytes += skb->len;
vcc->send(vcc, skb);
} else {
priv->stats.tx_dropped++;
dev_kfree_skb(skb);
}
}
static int static int
lec_send_packet(struct sk_buff *skb, struct net_device *dev) lec_send_packet(struct sk_buff *skb, struct net_device *dev)
{ {
...@@ -343,34 +360,10 @@ lec_send_packet(struct sk_buff *skb, struct net_device *dev) ...@@ -343,34 +360,10 @@ lec_send_packet(struct sk_buff *skb, struct net_device *dev)
DPRINTK("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\n", DPRINTK("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\n",
lec_h->h_dest[0], lec_h->h_dest[1], lec_h->h_dest[2], lec_h->h_dest[0], lec_h->h_dest[1], lec_h->h_dest[2],
lec_h->h_dest[3], lec_h->h_dest[4], lec_h->h_dest[5]); lec_h->h_dest[3], lec_h->h_dest[4], lec_h->h_dest[5]);
ATM_SKB(skb2)->vcc = send_vcc; lec_send(send_vcc, skb2, priv);
ATM_SKB(skb2)->iovcnt = 0;
ATM_SKB(skb2)->atm_options = send_vcc->atm_options;
DPRINTK("%s:sending to vpi:%d vci:%d\n", dev->name,
send_vcc->vpi, send_vcc->vci);
if (atm_may_send(send_vcc, skb2->len)) {
atomic_add(skb2->truesize, &send_vcc->tx_inuse);
priv->stats.tx_packets++;
priv->stats.tx_bytes += skb2->len;
send_vcc->send(send_vcc, skb2);
} else {
priv->stats.tx_dropped++;
dev_kfree_skb(skb2);
}
} }
ATM_SKB(skb)->vcc = send_vcc; lec_send(send_vcc, skb, priv);
ATM_SKB(skb)->iovcnt = 0;
ATM_SKB(skb)->atm_options = send_vcc->atm_options;
if (atm_may_send(send_vcc, skb->len)) {
atomic_add(skb->truesize, &send_vcc->tx_inuse);
priv->stats.tx_packets++;
priv->stats.tx_bytes += skb->len;
send_vcc->send(send_vcc, skb);
} else {
priv->stats.tx_dropped++;
dev_kfree_skb(skb);
}
#if 0 #if 0
/* Should we wait for card's device driver to notify us? */ /* Should we wait for card's device driver to notify us? */
...@@ -1614,6 +1607,10 @@ lec_arp_check_expire(unsigned long data) ...@@ -1614,6 +1607,10 @@ lec_arp_check_expire(unsigned long data)
&& &&
time_after_eq(now, entry->timestamp+ time_after_eq(now, entry->timestamp+
priv->path_switching_delay)) { priv->path_switching_delay)) {
struct sk_buff *skb;
while ((skb = skb_dequeue(&entry->tx_wait)))
lec_send(entry->vcc, skb, entry->priv);
entry->last_used = jiffies; entry->last_used = jiffies;
entry->status = entry->status =
ESI_FORWARD_DIRECT; ESI_FORWARD_DIRECT;
...@@ -2007,6 +2004,10 @@ lec_flush_complete(struct lec_priv *priv, unsigned long tran_id) ...@@ -2007,6 +2004,10 @@ lec_flush_complete(struct lec_priv *priv, unsigned long tran_id)
for (entry=priv->lec_arp_tables[i];entry;entry=entry->next) { for (entry=priv->lec_arp_tables[i];entry;entry=entry->next) {
if (entry->flush_tran_id == tran_id && if (entry->flush_tran_id == tran_id &&
entry->status == ESI_FLUSH_PENDING) { entry->status == ESI_FLUSH_PENDING) {
struct sk_buff *skb;
while ((skb = skb_dequeue(&entry->tx_wait)))
lec_send(entry->vcc, skb, entry->priv);
entry->status = ESI_FORWARD_DIRECT; entry->status = ESI_FORWARD_DIRECT;
DPRINTK("LEC_ARP: Flushed\n"); DPRINTK("LEC_ARP: Flushed\n");
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment