Netdev List
 help / color / mirror / Atom feed
* pcie_get_minimum_link returns 0 width
From: Yuval Mintz @ 2013-08-25 11:21 UTC (permalink / raw)
  To: jacob.e.keller@intel.com
  Cc: bhelgaas@google.com, linux-pci@vger.kernel.org,
	netdev@vger.kernel.org
In-Reply-To: <20130825100157.GA16500@lb-tlvb-yuvalmin.il.broadcom.com>

Hi,

I tried adding support for the newly added 'pcie_get_minimum_link' into the
bnx2x driver, but found out the some of my devices started showing width x0.

By adding debug prints, I've found out there were devices up the chain that
Showed 0 when their PCI_EXP_LNKSTA was read by said function.
However, when I tried looking via lspci the output claimed the width was x4.

lspci -vt output:
[0000:00]-+-00.0  Intel Corporation 5000P Chipset Memory Controller Hub
	     +-02.0-[09-12]--+-00.0-[0a-11]--+-00.0-[0b-0d]--
					     +-01.0-[0e-10]--+-00.0  Broadcom
					Corporation NetXtreme II BCM57710
					10-Gigabit PCIe [Everest]

Where:
00:02.0 PCI bridge: Intel Corporation 5000 Series Chipset PCI Express x4 Port
2 (rev 93)
09:00.0 PCI bridge: Intel Corporation 6311ESB/6321ESB PCI Express Upstream
Port (rev 01)
0a:01.0 PCI bridge: Intel Corporation 6311ESB/6321ESB PCI Express
Downstream Port E2 (rev 01)
0e:00.0 Ethernet controller: Broadcom Corporation NetXtreme II BCM57710
10-Gigabit PCIe [Everest] (rev 01)

The output for "lspci -vvvv | grep LnkSta for all four is:
LnkSta:	Speed 2.5GT/s, Width x4, TrErr- Train- SlotClk+ DLActive- BWMgmt-
ABWMgmt-

But added prints inside the function's loop show:
LnkSta 1041 [000e:00.00]
LnkSta 0000 [000a:01.00]
LnkSta 0000 [0009:00.00]
LnkSta 3041 [0000:02.00]
(PCI_EXP_LNKSTA value, bus->number, PCI_SLOT, PCI_FUNC)

Thanks,
Yuval

^ permalink raw reply

* [PATCH net] net: add cpu_relax to busy poll loop
From: Eliezer Tamir @ 2013-08-25  7:23 UTC (permalink / raw)
  To: David Miller; +Cc: linux-kernel, netdev, Eliezer Tamir

Add a cpu_relaxt to sk_busy_loop.

Julie Cummings reported performance issues when hyperthreading is on.
Arjan van de Ven observed that we should have a cpu_relax() in the
busy poll loop.

Reported-by: Julie Cummings <julie.a.cummings@intel.com>
Signed-off-by: Eliezer Tamir <eliezer.tamir@linux.intel.com>
---

 include/net/busy_poll.h |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/include/net/busy_poll.h b/include/net/busy_poll.h
index 8a358a2..829627d 100644
--- a/include/net/busy_poll.h
+++ b/include/net/busy_poll.h
@@ -123,6 +123,7 @@ static inline bool sk_busy_loop(struct sock *sk, int nonblock)
 			/* local bh are disabled so it is ok to use _BH */
 			NET_ADD_STATS_BH(sock_net(sk),
 					 LINUX_MIB_BUSYPOLLRXPACKETS, rc);
+		cpu_relax();
 
 	} while (!nonblock && skb_queue_empty(&sk->sk_receive_queue) &&
 		 !need_resched() && !busy_loop_timeout(end_time));

^ permalink raw reply related

* Re: [PATCH net-next] pkt_sched: fq: Fair Queue packet scheduler
From: David Miller @ 2013-08-25  6:53 UTC (permalink / raw)
  To: eric.dumazet; +Cc: netdev
In-Reply-To: <1377400082.8828.100.camel@edumazet-glaptop>


This depends upon your TCP patch, I knew this but you really should
be explicit about dependencies. :-)

And in any event I asked for a small change to the TCP patch, so...
it's not even in my queue right now.

^ permalink raw reply

* [PATCH net-next] pkt_sched: fq: Fair Queue packet scheduler
From: Eric Dumazet @ 2013-08-25  3:08 UTC (permalink / raw)
  To: David Miller; +Cc: netdev

From: Eric Dumazet <edumazet@google.com>

Fair Queue packet scheduler with optional per flow rate shaping.

- Uses perfect flow match (not stochastic hash like SFQ/FQ_codel)
- Uses the new_flow/old_flow separation from FQ_codel
- Special FIFO queue for high prio packets (no need for PRIO + FQ)
- Uses a hash table of RB trees to locate the flows at enqueue() time
- Smart on demand gc (at enqueue() time, RB tree lookup evicts old
  unused flows)
- Dynamic memory allocations.
- Designed to allow millions of concurrent flows per Qdisc.
- Small memory footprint : ~2K per Qdisc, and 96 bytes per flow.
- Single high resolution timer for throttled flows (if any).
- One RB tree to link throttled flows.
- Ability to have a max rate per flow. We might add a socket option
  to add per socket limitation.

Attempts have been made to add TCP pacing in TCP stack, but this
seems to add complex code to an already complex stack.

TCP pacing is welcomed for flows having idle times, as the cwnd
permits TCP stack to queue a possibly large number of packets.

This removes the 'slow start after idle' choice, hitting badly
large BDP flows.

Nicely spaced packets : here interface is 10Gbit, but flow bottleneck is
~100Mbit

cwin is big, yet FQ avoids the typical burst generated by TCP
(as in netperf TCP_RR -- -r 200000,200000)

04:29:48.340246 IP A > B: P 349144:349320(176) ack 200001 win 6431 <nop,nop,timestamp 244267845 2106896>
04:29:48.340270 IP B > A: . 200001:226065(26064) ack 349320 win 5204 <nop,nop,timestamp 2106905 244267845>
04:29:48.340830 IP B > A: . 226065:252129(26064) ack 349320 win 5204 <nop,nop,timestamp 2106905 244267845>
04:29:48.341354 IP A > B: . ack 223169 win 6431 <nop,nop,timestamp 244267853 2106905>
04:29:48.341392 IP B > A: . 252129:278193(26064) ack 349320 win 5204 <nop,nop,timestamp 2106905 244267845>
04:29:48.341891 IP B > A: . 278193:304257(26064) ack 349320 win 5204 <nop,nop,timestamp 2106905 244267845>
04:29:48.342392 IP B > A: . 304257:330321(26064) ack 349320 win 5204 <nop,nop,timestamp 2106905 244267845>
04:29:48.342892 IP B > A: . 330321:356385(26064) ack 349320 win 5204 <nop,nop,timestamp 2106905 244267845>
04:29:48.343077 IP A > B: . ack 226065 win 6431 <nop,nop,timestamp 244267854 2106905>
04:29:48.343319 IP A > B: . ack 249233 win 6431 <nop,nop,timestamp 244267855 2106905>
04:29:48.343393 IP B > A: . 356385:382449(26064) ack 349320 win 5204 <nop,nop,timestamp 2106905 244267845>
04:29:48.343808 IP B > A: . 382449:399825(17376) ack 349320 win 5204 <nop,nop,timestamp 2106906 244267853>
04:29:48.344085 IP B > A: P 399825:400001(176) ack 349320 win 5204 <nop,nop,timestamp 2106906 244267853>
04:29:48.345174 IP A > B: . ack 252129 win 6431 <nop,nop,timestamp 244267856 2106905>
04:29:48.345414 IP A > B: . ack 275297 win 6431 <nop,nop,timestamp 244267857 2106905>
04:29:48.347268 IP A > B: . ack 278193 win 6431 <nop,nop,timestamp 244267859 2106905>
04:29:48.347507 IP A > B: . ack 301361 win 6431 <nop,nop,timestamp 244267859 2106905>

TCP timestamps show that most packets were queued in the same ms
timeframe (TSval 2106905), but FQ managed to send them right
in time to avoid a big burst, and fill the pipe.

Signed-off-by: Eric Dumazet <edumazet@google.com>
---
 include/uapi/linux/pkt_sched.h |   34 +
 net/sched/Kconfig              |   14 
 net/sched/Makefile             |    1 
 net/sched/sch_fq.c             |  771 +++++++++++++++++++++++++++++++
 4 files changed, 820 insertions(+)

diff --git a/include/uapi/linux/pkt_sched.h b/include/uapi/linux/pkt_sched.h
index 09d62b92..ed434c5 100644
--- a/include/uapi/linux/pkt_sched.h
+++ b/include/uapi/linux/pkt_sched.h
@@ -744,4 +744,38 @@ struct tc_fq_codel_xstats {
 	};
 };
 
+/* FQ */
+
+enum {
+	TCA_FQ_UNSPEC,
+
+	TCA_FQ_PLIMIT,		/* limit of total number of packets in queue */
+
+	TCA_FQ_FLOW_PLIMIT,	/* limit of packets per flow */
+
+	TCA_FQ_QUANTUM,		/* RR quantum */
+
+	TCA_FQ_RATE_ENABLE,	/* enable/disable rate limiting */
+
+	TCA_FQ_FLOW_DEFAULT_RATE,/* for sockets with unspecified sk_rate,
+				  * use the following rate
+				  */
+
+	TCA_FQ_FLOW_MAX_RATE,	/* per flow max rate */
+
+	TCA_FQ_BUCKETS_LOG,	/* log2(number of buckets) */
+	__TCA_FQ_MAX
+};
+
+#define TCA_FQ_MAX	(__TCA_FQ_MAX - 1)
+
+struct tc_fq_qd_stats {
+	__u64	gc_flows;
+	__u64	highprio_packets;
+	__u64	tcp_retrans;
+	__u64	throttled;
+	__u64	flows_plimit;
+	__u64	pkts_too_long;
+	__u64	allocation_errors;
+};
 #endif
diff --git a/net/sched/Kconfig b/net/sched/Kconfig
index 235e01a..c03a32a 100644
--- a/net/sched/Kconfig
+++ b/net/sched/Kconfig
@@ -272,6 +272,20 @@ config NET_SCH_FQ_CODEL
 
 	  If unsure, say N.
 
+config NET_SCH_FQ
+	tristate "Fair Queue"
+	help
+	  Say Y here if you want to use the FQ packet scheduling algorithm.
+
+	  FQ does flow separation, and is able to respect pacing requirements
+	  set by TCP stack into sk->sk_pacing_rate (for localy generated
+	  traffic)
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called sch_fq.
+
+	  If unsure, say N.
+
 config NET_SCH_INGRESS
 	tristate "Ingress Qdisc"
 	depends on NET_CLS_ACT
diff --git a/net/sched/Makefile b/net/sched/Makefile
index 978cbf0..e5f9abe 100644
--- a/net/sched/Makefile
+++ b/net/sched/Makefile
@@ -39,6 +39,7 @@ obj-$(CONFIG_NET_SCH_CHOKE)	+= sch_choke.o
 obj-$(CONFIG_NET_SCH_QFQ)	+= sch_qfq.o
 obj-$(CONFIG_NET_SCH_CODEL)	+= sch_codel.o
 obj-$(CONFIG_NET_SCH_FQ_CODEL)	+= sch_fq_codel.o
+obj-$(CONFIG_NET_SCH_FQ)	+= sch_fq.o
 
 obj-$(CONFIG_NET_CLS_U32)	+= cls_u32.o
 obj-$(CONFIG_NET_CLS_ROUTE4)	+= cls_route.o
diff --git a/net/sched/sch_fq.c b/net/sched/sch_fq.c
new file mode 100644
index 0000000..87a054d
--- /dev/null
+++ b/net/sched/sch_fq.c
@@ -0,0 +1,771 @@
+/*
+ * net/sched/sch_fq.c Fair Queue Packet Scheduler (per flow pacing)
+ *
+ *  Copyright (C) 2013 Eric Dumazet <edumazet@google.com>
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ *
+ *  Meant to be used for localy generated traffic :
+ *  Fast classification depends on skb->sk being set before reaching us.
+ *  If not, (router workload), we use rxhash as fallback, with 32 bits wide hash.
+ *  All packets belonging to a socket are considered as a 'flow'.
+ *
+ *  Flows are dynamically allocated and stored in a hash table of RB trees
+ *  They are also part of one Round Robin 'queues' (new or old flows)
+ *
+ *  Burst avoidance (aka pacing) capability :
+ *  Transport (eg TCP) can set in sk->sk_pacing_rate a rate, enqueue a
+ *  bunch of packets, and this packet scheduler adds delay between
+ *  packets to respect rate limitation.
+ *
+ *  enqueue() :
+ *   - lookup one RB tree (out of 256 or more) to find the flow.
+ *     If non existent flow, create it, add it to the tree.
+ *     Add skb to the per flow list of skb (fifo).
+ *   - Use a special fifo for high prio packets
+ *
+ *  dequeue() : serves flows in Round Robin
+ *  Note : When a flow becomes empty, we do not immediately remove it from
+ *  rb trees, for performance reasons (its expected to send additional packets,
+ *  or SLAB cache will reuse socket for another flow)
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/jiffies.h>
+#include <linux/string.h>
+#include <linux/in.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/slab.h>
+#include <linux/rbtree.h>
+#include <linux/hash.h>
+#include <net/netlink.h>
+#include <net/pkt_sched.h>
+#include <net/sock.h>
+#include <net/tcp_states.h>
+
+/*
+ * Per flow structure, dynamically allocated
+ */
+struct fq_flow {
+	struct sk_buff	*head; /* list of skbs for this flow : first skb */
+	union {
+		struct sk_buff *tail;	/* last skb in the list */
+		unsigned long  age;	/* jiffies when flow was emptied, for gc */
+	};
+	struct rb_node	fq_node; /* anchor in fq_root[] trees */
+	struct sock	*sk;
+	int		qlen;	/* number of packets in flow queue */
+	int		deficit;
+	struct fq_flow *next;	/* next pointer in RR lists, or &detached */
+
+	struct rb_node  rate_node; /* anchor in q->delayed tree */
+	u64		time_next_packet;
+};
+
+struct fq_flow_head {
+	struct fq_flow *first;
+	struct fq_flow *last;
+};
+
+struct fq_sched_data {
+	struct fq_flow_head new_flows;
+
+	struct fq_flow_head old_flows;
+
+	struct rb_root	delayed; /* for rate limited flows */
+	u64		time_next_delayed_flow;
+
+	struct fq_flow	internal;	/* for non classified or high prio packets */
+	u32		quantum;
+	u32		flow_default_rate;/* rate per flow : bytes per second */
+	u32		flow_max_rate;	/* optional max rate per flow */
+	u32		flow_plimit;	/* max packets per flow */
+	struct rb_root	*fq_root;
+	u8		rate_enable;
+	u8		fq_trees_log;
+
+	u32		flows;
+	u32		inactive_flows;
+	u32		throttled_flows;
+
+	u64		stat_gc_flows;
+	u64		stat_internal_packets;
+	u64		stat_tcp_retrans;
+	u64		stat_throttled;
+	u64		stat_flows_plimit;
+	u64		stat_pkts_too_long;
+	u64		stat_allocation_errors;
+	struct qdisc_watchdog watchdog;
+};
+
+/* special value to mark a detached flow (not on old/new list) */
+static struct fq_flow detached, throttled;
+
+static void fq_flow_set_detached(struct fq_flow *f)
+{
+	f->next = &detached;
+}
+
+static bool fq_flow_is_detached(const struct fq_flow *f)
+{
+	return f->next == &detached;
+}
+
+static void fq_flow_set_throttled(struct fq_sched_data *q, struct fq_flow *f)
+{
+	struct rb_node **p = &q->delayed.rb_node, *parent = NULL;
+
+	while (*p) {
+		struct fq_flow *aux;
+
+		parent = *p;
+		aux = container_of(parent, struct fq_flow, rate_node);
+		if (f->time_next_packet >= aux->time_next_packet)
+			p = &parent->rb_right;
+		else
+			p = &parent->rb_left;
+	}
+	rb_link_node(&f->rate_node, parent, p);
+	rb_insert_color(&f->rate_node, &q->delayed);
+	q->throttled_flows++;
+	q->stat_throttled++;
+
+	f->next = &throttled;
+	if (q->time_next_delayed_flow > f->time_next_packet)
+		q->time_next_delayed_flow = f->time_next_packet;
+}
+
+
+static struct kmem_cache *fq_flow_cachep __read_mostly;
+
+static void fq_flow_add_tail(struct fq_flow_head *head, struct fq_flow *flow)
+{
+	if (head->first)
+		head->last->next = flow;
+	else
+		head->first = flow;
+	head->last = flow;
+	flow->next = NULL;
+}
+
+/* limit number of collected flows per round */
+#define FQ_GC_MAX 8
+#define FQ_GC_AGE (3*HZ)
+
+static bool fq_gc_candidate(const struct fq_flow *f)
+{
+	return fq_flow_is_detached(f) &&
+	       time_after(jiffies, f->age + FQ_GC_AGE);
+}
+
+static void fq_gc(struct fq_sched_data *q,
+		  struct rb_root *root,
+		  struct sock *sk)
+{
+	struct fq_flow *f, *tofree[FQ_GC_MAX];
+	struct rb_node **p, *parent;
+	int fcnt = 0;
+
+	p = &root->rb_node;
+	parent = NULL;
+	while (*p) {
+		parent = *p;
+
+		f = container_of(parent, struct fq_flow, fq_node);
+		if (f->sk == sk)
+			break;
+
+		if (fq_gc_candidate(f)) {
+			tofree[fcnt++] = f;
+			if (fcnt == FQ_GC_MAX)
+				break;
+		}
+
+		if (f->sk > sk)
+			p = &parent->rb_right;
+		else
+			p = &parent->rb_left;
+	}
+
+	q->flows -= fcnt;
+	q->inactive_flows -= fcnt;
+	q->stat_gc_flows += fcnt;
+	while (fcnt) {
+		struct fq_flow *f = tofree[--fcnt];
+
+		rb_erase(&f->fq_node, root);
+		kmem_cache_free(fq_flow_cachep, f);
+	}
+}
+
+static const u8 prio2band[TC_PRIO_MAX + 1] = {
+	1, 2, 2, 2, 1, 2, 0, 0 , 1, 1, 1, 1, 1, 1, 1, 1
+};
+
+static struct fq_flow *fq_classify(struct sk_buff *skb, struct fq_sched_data *q)
+{
+	struct rb_node **p, *parent;
+	struct sock *sk = skb->sk;
+	struct rb_root *root;
+	struct fq_flow *f;
+	int band;
+
+	/* warning: no starvation prevention... */
+	band = prio2band[skb->priority & TC_PRIO_MAX];
+	if (unlikely(band == 0))
+		return &q->internal;
+
+	if (unlikely(!sk)) {
+		/* By forcing low order bit to 1, we make sure to not
+		 * collide with a local flow (socket pointers are word aligned)
+		 */
+		sk = (struct sock *)(skb_get_rxhash(skb) | 1L);
+	}
+
+	root = &q->fq_root[hash_32((u32)(long)sk, q->fq_trees_log)];
+
+	if (q->flows >= (2U << q->fq_trees_log) &&
+	    q->inactive_flows > q->flows/2)
+		fq_gc(q, root, sk);
+
+	p = &root->rb_node;
+	parent = NULL;
+	while (*p) {
+		parent = *p;
+
+		f = container_of(parent, struct fq_flow, fq_node);
+		if (f->sk == sk)
+			return f;
+
+		if (f->sk > sk)
+			p = &parent->rb_right;
+		else
+			p = &parent->rb_left;
+	}
+
+	f = kmem_cache_zalloc(fq_flow_cachep, GFP_ATOMIC | __GFP_NOWARN);
+	if (unlikely(!f)) {
+		q->stat_allocation_errors++;
+		return &q->internal;
+	}
+	fq_flow_set_detached(f);
+	f->sk = sk;
+
+	rb_link_node(&f->fq_node, parent, p);
+	rb_insert_color(&f->fq_node, root);
+
+	q->flows++;
+	q->inactive_flows++;
+	return f;
+}
+
+
+/* remove one skb from head of flow queue */
+static struct sk_buff *fq_dequeue_head(struct fq_flow *flow)
+{
+	struct sk_buff *skb = flow->head;
+
+	if (skb) {
+		flow->head = skb->next;
+		skb->next = NULL;
+		flow->qlen--;
+	}
+	return skb;
+}
+
+/* We might add in the future detection of retransmits
+ * For the time being, just return false
+ */
+static bool skb_is_retransmit(struct sk_buff *skb)
+{
+	return false;
+}
+
+/* add skb to flow queue
+ * flow queue is a linked list, kind of FIFO, except for TCP retransmits
+ * We special case tcp retransmits to be transmitted before other packets.
+ * We rely on fact that TCP retransmits are unlikely, so we do not waste
+ * a separate queue or a pointer.
+ * head->  [retrans pkt 1]
+ *         [retrans pkt 2]
+ *         [ normal pkt 1]
+ *         [ normal pkt 2]
+ *         [ normal pkt 3]
+ * tail->  [ normal pkt 4]
+ */
+static void flow_queue_add(struct fq_flow *flow, struct sk_buff *skb)
+{
+	struct sk_buff *prev, *head = flow->head;
+
+	skb->next = NULL;
+	if (!head) {
+		flow->head = skb;
+		flow->tail = skb;
+		return;
+	}
+	if (likely(!skb_is_retransmit(skb))) {
+		flow->tail->next = skb;
+		flow->tail = skb;
+		return;
+	}
+
+	/* This skb is a tcp retransmit,
+	 * find the last retrans packet in the queue
+	 */
+	prev = NULL;
+	while (skb_is_retransmit(head)) {
+		prev = head;
+		head = head->next;
+		if (!head)
+			break;
+	}
+	if (!prev) { /* no rtx packet in queue, become the new head */
+		skb->next = flow->head;
+		flow->head = skb;
+	} else {
+		if (prev == flow->tail)
+			flow->tail = skb;
+		else
+			skb->next = prev->next;
+		prev->next = skb;
+	}
+}
+
+static int fq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
+{
+	struct fq_sched_data *q = qdisc_priv(sch);
+	struct fq_flow *f;
+
+	if (sch->q.qlen >= sch->limit)
+		return qdisc_drop(skb, sch);
+
+	f = fq_classify(skb, q);
+	if (f->qlen >= q->flow_plimit && f != &q->internal) {
+		q->stat_flows_plimit++;
+		return qdisc_drop(skb, sch);
+	}
+
+	f->qlen++;
+	flow_queue_add(f, skb);
+	if (skb_is_retransmit(skb))
+		q->stat_tcp_retrans++;
+	sch->qstats.backlog += qdisc_pkt_len(skb);
+	if (fq_flow_is_detached(f)) {
+		fq_flow_add_tail(&q->new_flows, f);
+		f->deficit = q->quantum;
+		q->inactive_flows--;
+		qdisc_unthrottled(sch);
+	}
+	if (f == &q->internal) {
+		q->stat_internal_packets++;
+		qdisc_unthrottled(sch);
+	}
+	sch->q.qlen++;
+
+	return NET_XMIT_SUCCESS;
+}
+
+static void fq_check_throttled(struct fq_sched_data *q, u64 now)
+{
+	struct rb_node *p;
+
+	if (q->time_next_delayed_flow > now)
+		return;
+
+	q->time_next_delayed_flow = ~0ULL;
+	while ((p = rb_first(&q->delayed)) != NULL) {
+		struct fq_flow *f = container_of(p, struct fq_flow, rate_node);
+		if (f->time_next_packet > now) {
+			q->time_next_delayed_flow = f->time_next_packet;
+			break;
+		}
+		rb_erase(p, &q->delayed);
+		q->throttled_flows--;
+		fq_flow_add_tail(&q->old_flows, f);
+	}
+}
+
+static struct sk_buff *fq_dequeue(struct Qdisc *sch)
+{
+	struct fq_sched_data *q = qdisc_priv(sch);
+	u64 now = ktime_to_ns(ktime_get());
+	struct fq_flow_head *head;
+	struct sk_buff *skb;
+	struct fq_flow *f;
+
+	skb = fq_dequeue_head(&q->internal);
+	if (skb)
+		goto out;
+	fq_check_throttled(q, now);
+begin:
+	head = &q->new_flows;
+	if (!head->first) {
+		head = &q->old_flows;
+		if (!head->first) {
+			if (q->time_next_delayed_flow != ~0ULL)
+				qdisc_watchdog_schedule_ns(&q->watchdog,
+							   q->time_next_delayed_flow);
+			return NULL;
+		}
+	}
+	f = head->first;
+
+	if (f->deficit <= 0) {
+		f->deficit += q->quantum;
+		head->first = f->next;
+		fq_flow_add_tail(&q->old_flows, f);
+		goto begin;
+	}
+
+	if (f->head && now < f->time_next_packet) {
+		head->first = f->next;
+		fq_flow_set_throttled(q, f);
+		goto begin;
+	}
+
+	skb = fq_dequeue_head(f);
+	if (!skb) {
+		head->first = f->next;
+		/* force a pass through old_flows to prevent starvation */
+		if ((head == &q->new_flows) && q->old_flows.first) {
+			fq_flow_add_tail(&q->old_flows, f);
+		} else {
+			fq_flow_set_detached(f);
+			f->age = jiffies;
+			q->inactive_flows++;
+		}
+		goto begin;
+	}
+	f->deficit -= qdisc_pkt_len(skb);
+	f->time_next_packet = now;
+
+	/* TOCHECK : The TCP_TIME_WAIT test might be not needed,
+	 * egress/ingress
+	 */
+
+	if (q->rate_enable && skb->sk && skb->sk->sk_state != TCP_TIME_WAIT) {
+		u32 rate = skb->sk->sk_pacing_rate ?: q->flow_default_rate;
+	
+		rate = min(rate, q->flow_max_rate);
+		if (rate) {
+			u64 len = (u64)qdisc_pkt_len(skb) * NSEC_PER_SEC;
+
+			do_div(len, rate);
+
+			/* Since socket rate can change later,
+			 * clamp the delay to 125 ms.
+			 * TODO: maybe segment the too big skb, as in commit
+			 * e43ac79a4bc ("sch_tbf: segment too big GSO packets")
+			 */
+			if (unlikely(len > 125 * NSEC_PER_MSEC)) {
+				len = 125 * NSEC_PER_MSEC;
+				q->stat_pkts_too_long++;
+			}
+
+			f->time_next_packet = now + len;
+		}
+	}
+out:
+	prefetch(&skb->end);
+	sch->qstats.backlog -= qdisc_pkt_len(skb);
+	qdisc_bstats_update(sch, skb);
+	sch->q.qlen--;
+	qdisc_unthrottled(sch);
+	return skb;
+}
+
+static void fq_reset(struct Qdisc *sch)
+{
+	struct sk_buff *skb;
+
+	while ((skb = fq_dequeue(sch)) != NULL)
+		kfree_skb(skb);
+}
+
+static void fq_rehash(struct fq_sched_data *q,
+		      struct rb_root *old_array, u32 old_log,
+		      struct rb_root *new_array, u32 new_log)
+{
+	struct rb_node *op, **np, *parent;
+	struct rb_root *oroot, *nroot;
+	struct fq_flow *of, *nf;
+	int fcnt = 0;
+	u32 idx;
+
+	for (idx = 0; idx < (1U << old_log); idx++) {
+		oroot = &old_array[idx];
+		while ((op = rb_first(oroot)) != NULL) {
+			rb_erase(op, oroot);
+			of = container_of(op, struct fq_flow, fq_node);
+			if (fq_gc_candidate(of)) {
+				fcnt++;
+				kmem_cache_free(fq_flow_cachep, of);
+				continue;
+			}
+			nroot = &new_array[hash_32((u32)(long)of->sk, new_log)];
+			
+			np = &nroot->rb_node;
+			parent = NULL;
+			while (*np) {
+				parent = *np;
+
+				nf = container_of(parent, struct fq_flow, fq_node);
+				BUG_ON(nf->sk == of->sk);
+
+				if (nf->sk > of->sk)
+					np = &parent->rb_right;
+				else
+					np = &parent->rb_left;
+			}
+
+			rb_link_node(&of->fq_node, parent, np);
+			rb_insert_color(&of->fq_node, nroot);
+		}
+	}
+	q->flows -= fcnt;
+	q->inactive_flows -= fcnt;
+	q->stat_gc_flows += fcnt;
+}
+
+static int fq_resize(struct fq_sched_data *q, u32 log)
+{
+	struct rb_root *array;
+	u32 idx;
+
+	if (q->fq_root && log == q->fq_trees_log)
+		return 0;
+
+	array = kmalloc(sizeof(struct rb_root) << log, GFP_KERNEL);
+	if (!array)
+		return -ENOMEM;
+
+	for (idx = 0; idx < (1U << log); idx++)
+		array[idx] = RB_ROOT;
+
+	if (q->fq_root) {
+		fq_rehash(q, q->fq_root, q->fq_trees_log, array, log);
+		kfree(q->fq_root);
+	}
+	q->fq_root = array;
+	q->fq_trees_log = log;
+
+	return 0;
+}
+
+static const struct nla_policy fq_policy[TCA_FQ_MAX + 1] = {
+	[TCA_FQ_PLIMIT]			= { .type = NLA_U32 },
+	[TCA_FQ_FLOW_PLIMIT]		= { .type = NLA_U32 },
+	[TCA_FQ_QUANTUM]		= { .type = NLA_U32 },
+	[TCA_FQ_RATE_ENABLE]		= { .type = NLA_U32 },
+	[TCA_FQ_FLOW_DEFAULT_RATE]	= { .type = NLA_U32 },
+	[TCA_FQ_FLOW_MAX_RATE]		= { .type = NLA_U32 },
+	[TCA_FQ_BUCKETS_LOG]		= { .type = NLA_U32 },
+};
+
+static int fq_change(struct Qdisc *sch, struct nlattr *opt)
+{
+	struct fq_sched_data *q = qdisc_priv(sch);
+	struct nlattr *tb[TCA_FQ_MAX + 1];
+	int err, drop_count = 0;
+	u32 fq_log;
+
+	if (!opt)
+		return -EINVAL;
+
+	err = nla_parse_nested(tb, TCA_FQ_MAX, opt, fq_policy);
+	if (err < 0)
+		return err;
+
+	sch_tree_lock(sch);
+
+	fq_log = q->fq_trees_log;
+
+	if (tb[TCA_FQ_BUCKETS_LOG]) {
+		u32 nval = nla_get_u32(tb[TCA_FQ_BUCKETS_LOG]);
+
+		if (nval >= 1 && nval <= ilog2(256*1024))
+			fq_log = nval;
+		else
+			err = -EINVAL;
+	}
+	if (tb[TCA_FQ_PLIMIT])
+		sch->limit = nla_get_u32(tb[TCA_FQ_PLIMIT]);
+
+	if (tb[TCA_FQ_FLOW_PLIMIT])
+		q->flow_plimit = nla_get_u32(tb[TCA_FQ_FLOW_PLIMIT]);
+
+	if (tb[TCA_FQ_QUANTUM])
+		q->quantum = nla_get_u32(tb[TCA_FQ_QUANTUM]);
+
+	if (tb[TCA_FQ_FLOW_DEFAULT_RATE])
+		q->flow_default_rate = nla_get_u32(tb[TCA_FQ_FLOW_DEFAULT_RATE]);
+
+	if (tb[TCA_FQ_FLOW_MAX_RATE])
+		q->flow_max_rate = nla_get_u32(tb[TCA_FQ_FLOW_MAX_RATE]);
+
+	if (tb[TCA_FQ_RATE_ENABLE]) {
+		u32 enable = nla_get_u32(tb[TCA_FQ_RATE_ENABLE]);
+
+		if (enable <= 1)
+			q->rate_enable = enable;
+		else
+			err = -EINVAL;
+	}
+
+	if (!err)
+		err = fq_resize(q, fq_log);
+
+	while (sch->q.qlen > sch->limit) {
+		struct sk_buff *skb = fq_dequeue(sch);
+
+		kfree_skb(skb);
+		drop_count++;
+	}
+	qdisc_tree_decrease_qlen(sch, drop_count);
+
+	sch_tree_unlock(sch);
+	return err;
+}
+
+static void fq_destroy(struct Qdisc *sch)
+{
+	struct fq_sched_data *q = qdisc_priv(sch);
+	struct rb_root *root;
+	struct rb_node *p;
+	unsigned int idx;
+
+	if (q->fq_root) {
+		for (idx = 0; idx < (1U << q->fq_trees_log); idx++) {
+			root = &q->fq_root[idx];
+			while ((p = rb_first(root)) != NULL) {
+				rb_erase(p, root);
+				kmem_cache_free(fq_flow_cachep,
+						container_of(p, struct fq_flow, fq_node));
+			}	
+		}
+		kfree(q->fq_root);
+	}
+	qdisc_watchdog_cancel(&q->watchdog);	
+}
+
+static int fq_init(struct Qdisc *sch, struct nlattr *opt)
+{
+	struct fq_sched_data *q = qdisc_priv(sch);
+	int err;
+
+	sch->limit = 10000;
+	q->flow_plimit = 100;
+	q->quantum = 2 * psched_mtu(qdisc_dev(sch));
+	q->flow_default_rate = 0;
+	q->flow_max_rate = ~0U;
+	q->rate_enable = 1;
+	q->new_flows.first = NULL;
+	q->old_flows.first = NULL;
+	q->delayed = RB_ROOT;
+	q->fq_root = NULL;
+	q->fq_trees_log = ilog2(256);
+	qdisc_watchdog_init(&q->watchdog, sch);
+
+	if (opt)
+		err = fq_change(sch, opt);
+	else
+		err = fq_resize(q, q->fq_trees_log);
+
+	return err;
+}
+
+static int fq_dump(struct Qdisc *sch, struct sk_buff *skb)
+{
+	struct fq_sched_data *q = qdisc_priv(sch);
+	struct nlattr *opts;
+
+	opts = nla_nest_start(skb, TCA_OPTIONS);
+	if (opts == NULL)
+		goto nla_put_failure;
+
+	if (nla_put_u32(skb, TCA_FQ_PLIMIT, sch->limit) ||
+	    nla_put_u32(skb, TCA_FQ_FLOW_PLIMIT, q->flow_plimit) ||
+	    nla_put_u32(skb, TCA_FQ_QUANTUM, q->quantum) ||
+	    nla_put_u32(skb, TCA_FQ_RATE_ENABLE, q->rate_enable) ||
+	    nla_put_u32(skb, TCA_FQ_FLOW_DEFAULT_RATE, q->flow_default_rate) ||
+	    nla_put_u32(skb, TCA_FQ_FLOW_MAX_RATE, q->flow_max_rate) ||
+	    nla_put_u32(skb, TCA_FQ_BUCKETS_LOG, q->fq_trees_log))
+		goto nla_put_failure;
+
+	nla_nest_end(skb, opts);
+	return skb->len;
+
+nla_put_failure:
+	return -1;
+}
+
+static int fq_dump_stats(struct Qdisc *sch, struct gnet_dump *d)
+{
+	struct fq_sched_data *q = qdisc_priv(sch);
+	struct tc_fq_qd_stats st = {
+		.gc_flows		= q->stat_gc_flows,
+		.highprio_packets	= q->stat_internal_packets,
+		.tcp_retrans		= q->stat_tcp_retrans,
+		.throttled		= q->stat_throttled,
+		.flows_plimit		= q->stat_flows_plimit,
+		.pkts_too_long		= q->stat_pkts_too_long,
+		.allocation_errors	= q->stat_allocation_errors,
+	};
+		
+	pr_debug("fq_dump_stats tcp_retrans %llu flows %u inactive %u gc %llu throttled %u/%llu internal %llu\n",
+		 q->stat_tcp_retrans, q->flows, q->inactive_flows,
+		 q->stat_gc_flows, q->throttled_flows, q->stat_throttled,
+		 q->stat_internal_packets);
+
+	return gnet_stats_copy_app(d, &st, sizeof(st));
+}
+
+static struct Qdisc_ops fq_qdisc_ops __read_mostly = {
+	.id		=	"fq",
+	.priv_size	=	sizeof(struct fq_sched_data),
+
+	.enqueue	=	fq_enqueue,
+	.dequeue	=	fq_dequeue,
+	.peek		=	qdisc_peek_dequeued,
+	.init		=	fq_init,
+	.reset		=	fq_reset,
+	.destroy	=	fq_destroy,
+	.change		=	fq_change,
+	.dump		=	fq_dump,
+	.dump_stats	=	fq_dump_stats,
+	.owner		=	THIS_MODULE,
+};
+
+static int __init fq_module_init(void)
+{
+	int ret;
+
+	fq_flow_cachep = kmem_cache_create("fq_flow_cache",
+					   sizeof(struct fq_flow),
+					   0, 0, NULL);
+	if (!fq_flow_cachep)
+		return -ENOMEM;
+
+	ret = register_qdisc(&fq_qdisc_ops);
+	if (ret)
+		kmem_cache_destroy(fq_flow_cachep);
+	return ret;
+}
+
+static void __exit fq_module_exit(void)
+{
+	unregister_qdisc(&fq_qdisc_ops);
+	kmem_cache_destroy(fq_flow_cachep);
+}
+
+module_init(fq_module_init)
+module_exit(fq_module_exit)
+MODULE_AUTHOR("Eric Dumazet");
+MODULE_LICENSE("GPL");

^ permalink raw reply related

* Re: [PATCH net-next] tcp: TSO packets automatic sizing
From: Eric Dumazet @ 2013-08-25  2:52 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, ncardwell, ycheng, vanj, therbert
In-Reply-To: <20130824.224644.683932175468680609.davem@davemloft.net>

On Sat, 2013-08-24 at 22:46 -0400, David Miller wrote:
> From: Eric Dumazet <eric.dumazet@gmail.com>
> Date: Fri, 23 Aug 2013 17:29:52 -0700
> 
> > After hearing many people over past years complaining against TSO being
> > bursty or even buggy, we are proud to present automatic sizing of TSO
> > packets.
> 
> Looks great.
> 
> > +	pr_debug("cwnd %u packets_out %u srtt %u -> rate = %llu bits\n",
> > +		 tp->snd_cwnd, tp->packets_out,
> > +		 jiffies_to_usecs(tp->srtt) >> 3, rate << 3);
> 
> I'd suggest you remove this though.
> 

Sure, but I found this very useful while debugging sch_fq.

CTRL=/sys/kernel/debug/dynamic_debug/control
echo "func tcp_rtt_estimator +p" >$CTRL
./netperf -l -1000000 -H lpq84
echo "func tcp_rtt_estimator -p" >$CTRL 

^ permalink raw reply

* Re: [PATCH net-next] tcp: TSO packets automatic sizing
From: David Miller @ 2013-08-25  2:46 UTC (permalink / raw)
  To: eric.dumazet; +Cc: netdev, ncardwell, ycheng, vanj, therbert
In-Reply-To: <1377304192.8828.43.camel@edumazet-glaptop>

From: Eric Dumazet <eric.dumazet@gmail.com>
Date: Fri, 23 Aug 2013 17:29:52 -0700

> After hearing many people over past years complaining against TSO being
> bursty or even buggy, we are proud to present automatic sizing of TSO
> packets.

Looks great.

> +	pr_debug("cwnd %u packets_out %u srtt %u -> rate = %llu bits\n",
> +		 tp->snd_cwnd, tp->packets_out,
> +		 jiffies_to_usecs(tp->srtt) >> 3, rate << 3);

I'd suggest you remove this though.

^ permalink raw reply

* Re: [PATCH net-next] tcp: TSO packets automatic sizing
From: Eric Dumazet @ 2013-08-24 20:28 UTC (permalink / raw)
  To: Neal Cardwell
  Cc: David Miller, netdev, Yuchung Cheng, Van Jacobson, Tom Herbert
In-Reply-To: <1377370594.8828.72.camel@edumazet-glaptop>

On Sat, 2013-08-24 at 11:56 -0700, Eric Dumazet wrote:

> Problem is that if the application does a sendmsg( 1 Mbytes) right after
> accept(), we'll cook 14KB TSO packets and are back to initial problem.
> 
> Quite frankly TSO advantage for servers sending replies that are 10MSS
> or less is thin, because we spend most of cpu cycles in socket
> setup/dismantle and ACK processing.
> 
> TSO is a win for sockets sending say more than 100KB, or even 1MB

Another interesting point having small packets at the beginning of the
connection when/if pacing is enabled in the (FQ) packet scheduler,
an incorrect initial rtt would have lower impact :

13:14:45.271930 IP 10.246.17.83.41052 > 10.246.17.84.41129: S 2688061178:2688061178(0) win 29200 <mss 1460,sackOK,timestamp 281602 0,nop,wscale 6>
13:14:45.322055 IP 10.246.17.84.41129 > 10.246.17.83.41052: S 1339982632:1339982632(0) ack 2688061179 win 28960 <mss 1460,sackOK,timestamp 146299869 281602,nop,wscale 7>
13:14:45.322126 IP 10.246.17.83.41052 > 10.246.17.84.41129: . ack 1 win 457 <nop,nop,timestamp 281652 146299869>
13:14:45.322245 IP 10.246.17.83.41052 > 10.246.17.84.41129: . 1:1449(1448) ack 1 win 457 <nop,nop,timestamp 281652 146299869>
13:14:45.324944 IP 10.246.17.83.41052 > 10.246.17.84.41129: . 1449:2897(1448) ack 1 win 457 <nop,nop,timestamp 281652 146299869>
13:14:45.327600 IP 10.246.17.83.41052 > 10.246.17.84.41129: . 2897:4345(1448) ack 1 win 457 <nop,nop,timestamp 281652 146299869>
13:14:45.330301 IP 10.246.17.83.41052 > 10.246.17.84.41129: . 4345:5793(1448) ack 1 win 457 <nop,nop,timestamp 281652 146299869>
13:14:45.333001 IP 10.246.17.83.41052 > 10.246.17.84.41129: . 5793:7241(1448) ack 1 win 457 <nop,nop,timestamp 281653 146299869>
13:14:45.335697 IP 10.246.17.83.41052 > 10.246.17.84.41129: . 7241:8689(1448) ack 1 win 457 <nop,nop,timestamp 281653 146299869>
13:14:45.338392 IP 10.246.17.83.41052 > 10.246.17.84.41129: . 8689:10137(1448) ack 1 win 457 <nop,nop,timestamp 281653 146299869>
13:14:45.341087 IP 10.246.17.83.41052 > 10.246.17.84.41129: . 10137:11585(1448) ack 1 win 457 <nop,nop,timestamp 281653 146299869>
13:14:45.343770 IP 10.246.17.83.41052 > 10.246.17.84.41129: . 11585:13033(1448) ack 1 win 457 <nop,nop,timestamp 281653 146299869>
13:14:45.346471 IP 10.246.17.83.41052 > 10.246.17.84.41129: . 13033:14481(1448) ack 1 win 457 <nop,nop,timestamp 281653 146299869>
13:14:45.372577 IP 10.246.17.84.41129 > 10.246.17.83.41052: . ack 1449 win 249 <nop,nop,timestamp 146299919 281652>

If the "ack 1449" coming back from client was coming sooner than expected,
this could change the srtt estimation and packet scheduler could
send remaining packets sooner.

This makes me think that srtt computation could be more precise.

First RTT sample sets SRTT=RTT

But second sample sets to SRTT = SRTT*7/8 + nRTT,
while it probably should do SRTT = (SRTT + nRTT)/2

Third sample also should do :  SRTT = SRTT*2/3 + nRTT/3
...

^ permalink raw reply

* [PATCH] net/cadence/macb: fix kernel Oops if no PHY were discovered during probe
From: Boris BREZILLON @ 2013-08-24 19:21 UTC (permalink / raw)
  To: Nicolas Ferre; +Cc: netdev, linux-kernel, linux-arm-kernel, Boris BREZILLON

Test the presence of a PHY device before printing attached PHY
informations.

Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com>
---
 drivers/net/ethernet/cadence/macb.c |    6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
index e866608..fd3b67f 100644
--- a/drivers/net/ethernet/cadence/macb.c
+++ b/drivers/net/ethernet/cadence/macb.c
@@ -1868,8 +1868,10 @@ static int __init macb_probe(struct platform_device *pdev)
 		    dev->irq, dev->dev_addr);
 
 	phydev = bp->phy_dev;
-	netdev_info(dev, "attached PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n",
-		    phydev->drv->name, dev_name(&phydev->dev), phydev->irq);
+	if (phydev)
+		netdev_info(dev, "attached PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n",
+			    phydev->drv->name, dev_name(&phydev->dev),
+			    phydev->irq);
 
 	return 0;
 
-- 
1.7.9.5

^ permalink raw reply related

* Re: [PATCH net-next] tcp: TSO packets automatic sizing
From: Eric Dumazet @ 2013-08-24 18:56 UTC (permalink / raw)
  To: Neal Cardwell
  Cc: David Miller, netdev, Yuchung Cheng, Van Jacobson, Tom Herbert
In-Reply-To: <CADVnQymvQz67k1_f4rRJxPVUFWL=rM5vnT-ZO1VPSxN-E0uzDA@mail.gmail.com>

On Fri, 2013-08-23 at 23:17 -0400, Neal Cardwell wrote:

> I love this! Can't wait to play with it.
> 

Totally agree ;)

> Rather than implicitly initializing sk_pacing_rate to 0, I'd suggest
> maybe initializing sk_pacing_rate to a value just high enough
> (TCP_INIT_CWND * mss / 1ms?) so that in the first transmit the
> connection can (as it does today) construct a single TSO jumbogram of
> TCP_INIT_CWND segments and send that in a single trip down through the
> stack. Hopefully this should keep CPU usage advantages of TSO for
> servers that spend most of their time sending replies that are 10MSS
> or less, while not making the on-the-wire behavior much burstier than
> it would be with the patch as it stands.
> 

Yes, this sounds an interesting idea. 

Problem is that if the application does a sendmsg( 1 Mbytes) right after
accept(), we'll cook 14KB TSO packets and are back to initial problem.

Quite frankly TSO advantage for servers sending replies that are 10MSS
or less is thin, because we spend most of cpu cycles in socket
setup/dismantle and ACK processing.

TSO is a win for sockets sending say more than 100KB, or even 1MB



> I am wondering about the aspect of the patch that sets sk_pacing_rate
> to 2x the current rate in tcp_rtt_estimator and then just has to
> divide by 2 again in tcp_xmit_size_goal(). It seems the 2x factor is
> natural in the packet scheduler context, but at first glance it feels
> to me like the multiplication by 2 should be an internal detail of the
> optional scheduler, not part of the sk_pacing_rate interface between
> the TCP and scheduling layer.

I would like to keep FQ as simple as possible, and let the transport
decide for appropriate strategy.

TCP should be the appropriate place to decide on precise delays between
packets. Packet scheduler will only execute the orders coming from TCP.

In this patch, I chose a 200% factor that is conservative enough to make
sure there will be no change in the ramp up. It can later be changed to
get finer control.

> 
> One thing I noticed: something about how the current patch shakes out
> causes a basic 10-MSS transfer to take an extra RTT, due to the last
> 2-segment packet having to wait for an ACK:
> 
> # cat iw10-base-case.pkt
> 0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3
> 0.000 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
> 0.000 bind(3, ..., ...) = 0
> 0.000 listen(3, 1) = 0
> 
> 0.100 < S 0:0(0) win 32792 <mss 1460,sackOK,nop,nop,nop,wscale 7>
> 0.100 > S. 0:0(0) ack 1 <mss 1460,nop,nop,sackOK,nop,wscale 6>
> 0.200 < . 1:1(0) ack 1 win 257
> 0.200 accept(3, ..., ...) = 4
> 
> 0.200 write(4, ..., 14600) = 14600
> 0.300 < . 1:1(0) ack 11681 win 257
> 
> ->
> 
> # ./packetdrill iw10-base-case.pkt
> 0.701287 cli > srv: S 0:0(0) win 32792 <mss 1460,sackOK,nop,nop,nop,wscale 7>
> 0.701367 srv > cli: S 2822928622:2822928622(0) ack 1 win 29200 <mss
> 1460,nop,nop,sackOK,nop,wscale 6>
> 0.801276 cli > srv: . ack 1 win 257
> 0.801365 srv > cli: . 1:2921(2920) ack 1 win 457
> 0.801376 srv > cli: . 2921:5841(2920) ack 1 win 457
> 0.801382 srv > cli: . 5841:8761(2920) ack 1 win 457
> 0.801386 srv > cli: . 8761:11681(2920) ack 1 win 457
> 0.901284 cli > srv: . ack 11681 win 257
> 0.901308 srv > cli: P 11681:14601(2920) ack 1 win 457
> 
> I'd try to isolate the exact cause, but it's a bit late in the evening
> for me to track this down at this point, and I'll be offline tomorrow.

Interesting, but I do not see this on normal ethernet device (bnx2x in
the following traces)

Trying different min_tso_segs exhibits expected different behavior (10
first MSS (14480 bytes of payload) sent in the same ms, no need to wait
an ACK. (RTT = 50ms in this setup)

echo 1 >/proc/sys/net/ipv4/tcp_min_tso_segs

10:40:35.333703 IP 10.246.17.83.50336 > 10.246.17.84.50267: S 3924987356:3924987356(0) win 29200 <mss 1460,sackOK,timestamp 64807623 0,nop,wscale 6>
10:40:35.383835 IP 10.246.17.84.50267 > 10.246.17.83.50336: S 151800535:151800535(0) ack 3924987357 win 28960 <mss 1460,sackOK,timestamp 137049930 64807623,nop,wscale 7>
10:40:35.383868 IP 10.246.17.83.50336 > 10.246.17.84.50267: . ack 1 win 457 <nop,nop,timestamp 64807673 137049930>
10:40:35.383936 IP 10.246.17.83.50336 > 10.246.17.84.50267: . 1:1449(1448) ack 1 win 457 <nop,nop,timestamp 64807673 137049930>
10:40:35.383943 IP 10.246.17.83.50336 > 10.246.17.84.50267: . 1449:2897(1448) ack 1 win 457 <nop,nop,timestamp 64807673 137049930>
10:40:35.383948 IP 10.246.17.83.50336 > 10.246.17.84.50267: . 2897:4345(1448) ack 1 win 457 <nop,nop,timestamp 64807673 137049930>
10:40:35.383952 IP 10.246.17.83.50336 > 10.246.17.84.50267: . 4345:5793(1448) ack 1 win 457 <nop,nop,timestamp 64807673 137049930>
10:40:35.383957 IP 10.246.17.83.50336 > 10.246.17.84.50267: . 5793:7241(1448) ack 1 win 457 <nop,nop,timestamp 64807673 137049930>
10:40:35.383961 IP 10.246.17.83.50336 > 10.246.17.84.50267: . 7241:8689(1448) ack 1 win 457 <nop,nop,timestamp 64807673 137049930>
10:40:35.383965 IP 10.246.17.83.50336 > 10.246.17.84.50267: . 8689:10137(1448) ack 1 win 457 <nop,nop,timestamp 64807673 137049930>
10:40:35.383968 IP 10.246.17.83.50336 > 10.246.17.84.50267: . 10137:11585(1448) ack 1 win 457 <nop,nop,timestamp 64807673 137049930>
10:40:35.383972 IP 10.246.17.83.50336 > 10.246.17.84.50267: . 11585:13033(1448) ack 1 win 457 <nop,nop,timestamp 64807673 137049930>
10:40:35.383975 IP 10.246.17.83.50336 > 10.246.17.84.50267: . 13033:14481(1448) ack 1 win 457 <nop,nop,timestamp 64807673 137049930>
10:40:35.434061 IP 10.246.17.84.50267 > 10.246.17.83.50336: . ack 1449 win 249 <nop,nop,timestamp 137049981 64807673>

echo 2 >/proc/sys/net/ipv4/tcp_min_tso_segs

10:45:24.280183 IP 10.246.17.83.36666 > 10.246.17.84.40648: S 1657754774:1657754774(0) win 29200 <mss 1460,sackOK,timestamp 65096569 0,nop,wscale 6>
10:45:24.330302 IP 10.246.17.84.40648 > 10.246.17.83.36666: S 362153932:362153932(0) ack 1657754775 win 28960 <mss 1460,sackOK,timestamp 137338877 65096569,nop,wscale 7>
10:45:24.330384 IP 10.246.17.83.36666 > 10.246.17.84.40648: . ack 1 win 457 <nop,nop,timestamp 65096620 137338877>
10:45:24.330477 IP 10.246.17.83.36666 > 10.246.17.84.40648: . 1:2897(2896) ack 1 win 457 <nop,nop,timestamp 65096620 137338877>
10:45:24.330497 IP 10.246.17.83.36666 > 10.246.17.84.40648: . 2897:5793(2896) ack 1 win 457 <nop,nop,timestamp 65096620 137338877>
10:45:24.330501 IP 10.246.17.83.36666 > 10.246.17.84.40648: . 5793:8689(2896) ack 1 win 457 <nop,nop,timestamp 65096620 137338877>
10:45:24.330665 IP 10.246.17.83.36666 > 10.246.17.84.40648: . 8689:11585(2896) ack 1 win 457 <nop,nop,timestamp 65096620 137338877>
10:45:24.330674 IP 10.246.17.83.36666 > 10.246.17.84.40648: . 11585:14481(2896) ack 1 win 457 <nop,nop,timestamp 65096620 137338877>
10:45:24.380592 IP 10.246.17.84.40648 > 10.246.17.83.36666: . ack 1449 win 249 <nop,nop,timestamp 137338927 65096620>

echo 3 >/proc/sys/net/ipv4/tcp_min_tso_segs

10:48:51.558662 IP 10.246.17.83.44835 > 10.246.17.84.56145: S 2572155347:2572155347(0) win 29200 <mss 1460,sackOK,timestamp 65303848 0,nop,wscale 6>
10:48:51.608797 IP 10.246.17.84.56145 > 10.246.17.83.44835: S 2206641454:2206641454(0) ack 2572155348 win 28960 <mss 1460,sackOK,timestamp 137546155 65303848,nop,wscale 7>
10:48:51.608824 IP 10.246.17.83.44835 > 10.246.17.84.56145: . ack 1 win 457 <nop,nop,timestamp 65303898 137546155>
10:48:51.608901 IP 10.246.17.83.44835 > 10.246.17.84.56145: . 1:4345(4344) ack 1 win 457 <nop,nop,timestamp 65303898 137546155>
10:48:51.608911 IP 10.246.17.83.44835 > 10.246.17.84.56145: . 4345:8689(4344) ack 1 win 457 <nop,nop,timestamp 65303898 137546155>
10:48:51.608917 IP 10.246.17.83.44835 > 10.246.17.84.56145: . 8689:13033(4344) ack 1 win 457 <nop,nop,timestamp 65303898 137546155>
10:48:51.608927 IP 10.246.17.83.44835 > 10.246.17.84.56145: . 13033:14481(1448) ack 1 win 457 <nop,nop,timestamp 65303898 137546155>
10:48:51.659018 IP 10.246.17.84.56145 > 10.246.17.83.44835: . ack 1449 win 249 <nop,nop,timestamp 137546206 65303898>
10:48:51.659102 IP 10.246.17.83.44835 > 10.246.17.84.56145: . 14481:17377(2896) ack 1 win 457 <nop,nop,timestamp 65303948 137546206>
10:48:51.659019 IP 10.246.17.84.56145 > 10.246.17.83.44835: . ack 2897 win 272 <nop,nop,timestamp 137546206 65303898>
10:48:51.659113 IP 10.246.17.83.44835 > 10.246.17.84.56145: P 17377:18825(1448) ack 1 win 457 <nop,nop,timestamp 65303948 137546206>
10:48:51.659124 IP 10.246.17.84.56145 > 10.246.17.83.44835: . ack 4345 win 295 <nop,nop,timestamp 137546206 65303898>

echo 4 >/proc/sys/net/ipv4/tcp_min_tso_segs

10:49:41.553016 IP 10.246.17.83.51499 > 10.246.17.84.37071: S 770187706:770187706(0) win 29200 <mss 1460,sackOK,timestamp 65353842 0,nop,wscale 6>
10:49:41.603149 IP 10.246.17.84.37071 > 10.246.17.83.51499: S 3342827191:3342827191(0) ack 770187707 win 28960 <mss 1460,sackOK,timestamp 137596150 65353842,nop,wscale 7>
10:49:41.603223 IP 10.246.17.83.51499 > 10.246.17.84.37071: . ack 1 win 457 <nop,nop,timestamp 65353892 137596150>
10:49:41.603307 IP 10.246.17.83.51499 > 10.246.17.84.37071: . 1:5793(5792) ack 1 win 457 <nop,nop,timestamp 65353893 137596150>
10:49:41.603317 IP 10.246.17.83.51499 > 10.246.17.84.37071: . 5793:11585(5792) ack 1 win 457 <nop,nop,timestamp 65353893 137596150>
10:49:41.603329 IP 10.246.17.83.51499 > 10.246.17.84.37071: . 11585:14481(2896) ack 1 win 457 <nop,nop,timestamp 65353893 137596150>
10:49:41.653448 IP 10.246.17.84.37071 > 10.246.17.83.51499: . ack 1449 win 249 <nop,nop,timestamp 137596200 65353893>
10:49:41.653531 IP 10.246.17.83.51499 > 10.246.17.84.37071: . 14481:17377(2896) ack 1 win 457 <nop,nop,timestamp 65353943 137596200>
10:49:41.653450 IP 10.246.17.84.37071 > 10.246.17.83.51499: . ack 2897 win 272 <nop,nop,timestamp 137596200 65353893>
10:49:41.653618 IP 10.246.17.83.51499 > 10.246.17.84.37071: . 17377:20273(2896) ack 1 win 457 <nop,nop,timestamp 65353943 137596200>

echo 5 >/proc/sys/net/ipv4/tcp_min_tso_segs

10:50:33.626270 IP 10.246.17.83.52633 > 10.246.17.84.33693: S 1635294551:1635294551(0) win 29200 <mss 1460,sackOK,timestamp 65405916 0,nop,wscale 6>
10:50:33.676407 IP 10.246.17.84.33693 > 10.246.17.83.52633: S 1023650170:1023650170(0) ack 1635294552 win 28960 <mss 1460,sackOK,timestamp 137648223 65405916,nop,wscale 7>
10:50:33.676489 IP 10.246.17.83.52633 > 10.246.17.84.33693: . ack 1 win 457 <nop,nop,timestamp 65405966 137648223>
10:50:33.676571 IP 10.246.17.83.52633 > 10.246.17.84.33693: . 1:7241(7240) ack 1 win 457 <nop,nop,timestamp 65405966 137648223>
10:50:33.676578 IP 10.246.17.83.52633 > 10.246.17.84.33693: . 7241:14481(7240) ack 1 win 457 <nop,nop,timestamp 65405966 137648223>
10:50:33.726706 IP 10.246.17.84.33693 > 10.246.17.83.52633: . ack 1449 win 249 <nop,nop,timestamp 137648273 65405966>
10:50:33.726707 IP 10.246.17.84.33693 > 10.246.17.83.52633: . ack 2897 win 272 <nop,nop,timestamp 137648273 65405966>
10:50:33.726792 IP 10.246.17.83.52633 > 10.246.17.84.33693: . 14481:20273(5792) ack 1 win 457 <nop,nop,timestamp 65406016 137648273>
10:50:33.726781 IP 10.246.17.84.33693 > 10.246.17.83.52633: . ack 4345 win 295 <nop,nop,timestamp 137648273 65405966>
10:50:33.726986 IP 10.246.17.84.33693 > 10.246.17.83.52633: . ack 5793 win 317 <nop,nop,timestamp 137648274 65405966>
10:50:33.727101 IP 10.246.17.84.33693 > 10.246.17.83.52633: . ack 7241 win 340 <nop,nop,timestamp 137648274 65405966>
10:50:33.727117 IP 10.246.17.83.52633 > 10.246.17.84.33693: P 20273:27513(7240) ack 1 win 457 <nop,nop,timestamp 65406016 137648274>
10:50:33.727258 IP 10.246.17.84.33693 > 10.246.17.83.52633: . ack 8689 win 340 <nop,nop,timestamp 137648274 65405966>
10:50:33.727408 IP 10.246.17.84.33693 > 10.246.17.83.52633: . ack 10137 win 340 <nop,nop,timestamp 137648274 65405966>

echo 6 >/proc/sys/net/ipv4/tcp_min_tso_segs

10:51:23.295063 IP 10.246.17.83.49096 > 10.246.17.84.43872: S 1841824181:1841824181(0) win 29200 <mss 1460,sackOK,timestamp 65455584 0,nop,wscale 6>
10:51:23.345207 IP 10.246.17.84.43872 > 10.246.17.83.49096: S 2837501410:2837501410(0) ack 1841824182 win 28960 <mss 1460,sackOK,timestamp 137697892 65455584,nop,wscale 7>
10:51:23.345237 IP 10.246.17.83.49096 > 10.246.17.84.43872: . ack 1 win 457 <nop,nop,timestamp 65455635 137697892>
10:51:23.345311 IP 10.246.17.83.49096 > 10.246.17.84.43872: . 1:8689(8688) ack 1 win 457 <nop,nop,timestamp 65455635 137697892>
10:51:23.345330 IP 10.246.17.83.49096 > 10.246.17.84.43872: . 8689:14481(5792) ack 1 win 457 <nop,nop,timestamp 65455635 137697892>
10:51:23.395453 IP 10.246.17.84.43872 > 10.246.17.83.49096: . ack 1449 win 249 <nop,nop,timestamp 137697942 65455635>
10:51:23.395454 IP 10.246.17.84.43872 > 10.246.17.83.49096: . ack 2897 win 272 <nop,nop,timestamp 137697942 65455635>
10:51:23.395544 IP 10.246.17.83.49096 > 10.246.17.84.43872: . 14481:20273(5792) ack 1 win 457 <nop,nop,timestamp 65455685 137697942>
10:51:23.395533 IP 10.246.17.84.43872 > 10.246.17.83.49096: . ack 4345 win 295 <nop,nop,timestamp 137697942 65455635>
10:51:23.395631 IP 10.246.17.83.49096 > 10.246.17.84.43872: . 20273:23169(2896) ack 1 win 457 <nop,nop,timestamp 65455685 137697942>
10:51:23.395746 IP 10.246.17.84.43872 > 10.246.17.83.49096: . ack 5793 win 317 <nop,nop,timestamp 137697942 65455635>
10:51:23.395854 IP 10.246.17.84.43872 > 10.246.17.83.49096: . ack 7241 win 340 <nop,nop,timestamp 137697943 65455635>
10:51:23.396049 IP 10.246.17.84.43872 > 10.246.17.83.49096: . ack 8689 win 340 <nop,nop,timestamp 137697943 65455635>
10:51:23.396199 IP 10.246.17.83.49096 > 10.246.17.84.43872: P 23169:31857(8688) ack 1 win 457 <nop,nop,timestamp 65455685 137697943>

echo 7 >/proc/sys/net/ipv4/tcp_min_tso_segs

10:51:58.219334 IP 10.246.17.83.58882 > 10.246.17.84.41983: S 3763353310:3763353310(0) win 29200 <mss 1460,sackOK,timestamp 65490509 0,nop,wscale 6>
10:51:58.269455 IP 10.246.17.84.41983 > 10.246.17.83.58882: S 1445588492:1445588492(0) ack 3763353311 win 28960 <mss 1460,sackOK,timestamp 137732816 65490509,nop,wscale 7>
10:51:58.269536 IP 10.246.17.83.58882 > 10.246.17.84.41983: . ack 1 win 457 <nop,nop,timestamp 65490559 137732816>
10:51:58.269634 IP 10.246.17.83.58882 > 10.246.17.84.41983: . 1:10137(10136) ack 1 win 457 <nop,nop,timestamp 65490559 137732816>
10:51:58.269646 IP 10.246.17.83.58882 > 10.246.17.84.41983: . 10137:14481(4344) ack 1 win 457 <nop,nop,timestamp 65490559 137732816>
10:51:58.319765 IP 10.246.17.84.41983 > 10.246.17.83.58882: . ack 1449 win 249 <nop,nop,timestamp 137732866 65490559>
10:51:58.319846 IP 10.246.17.83.58882 > 10.246.17.84.41983: . 14481:17377(2896) ack 1 win 457 <nop,nop,timestamp 65490609 137732866>
10:51:58.319767 IP 10.246.17.84.41983 > 10.246.17.83.58882: . ack 2897 win 272 <nop,nop,timestamp 137732866 65490559>
10:51:58.319843 IP 10.246.17.84.41983 > 10.246.17.83.58882: . ack 4345 win 295 <nop,nop,timestamp 137732867 65490559>
10:51:58.319911 IP 10.246.17.83.58882 > 10.246.17.84.41983: . 17377:23169(5792) ack 1 win 457 <nop,nop,timestamp 65490609 137732867>
10:51:58.320068 IP 10.246.17.84.41983 > 10.246.17.83.58882: . ack 5793 win 317 <nop,nop,timestamp 137732867 65490559>
10:51:58.320180 IP 10.246.17.84.41983 > 10.246.17.83.58882: . ack 7241 win 340 <nop,nop,timestamp 137732867 65490559>
10:51:58.320287 IP 10.246.17.84.41983 > 10.246.17.83.58882: . ack 8689 win 340 <nop,nop,timestamp 137732867 65490559>
10:51:58.320295 IP 10.246.17.83.58882 > 10.246.17.84.41983: . 23169:31857(8688) ack 1 win 457 <nop,nop,timestamp 65490610 137732867>
10:51:58.320496 IP 10.246.17.84.41983 > 10.246.17.83.58882: . ack 10137 win 340 <nop,nop,timestamp 137732867 65490559>
10:51:58.320513 IP 10.246.17.83.58882 > 10.246.17.84.41983: . 31857:33305(1448) ack 1 win 457 <nop,nop,timestamp 65490610 137732867>

echo 8 >/proc/sys/net/ipv4/tcp_min_tso_segs

10:52:50.398941 IP 10.246.17.83.32908 > 10.246.17.84.65099: S 678482142:678482142(0) win 29200 <mss 1460,sackOK,timestamp 65542688 0,nop,wscale 6>
10:52:50.449061 IP 10.246.17.84.65099 > 10.246.17.83.32908: S 3229813359:3229813359(0) ack 678482143 win 28960 <mss 1460,sackOK,timestamp 137784996 65542688,nop,wscale 7>
10:52:50.449146 IP 10.246.17.83.32908 > 10.246.17.84.65099: . ack 1 win 457 <nop,nop,timestamp 65542738 137784996>
10:52:50.449258 IP 10.246.17.83.32908 > 10.246.17.84.65099: . 1:11585(11584) ack 1 win 457 <nop,nop,timestamp 65542739 137784996>
10:52:50.449384 IP 10.246.17.83.32908 > 10.246.17.84.65099: . 11585:14481(2896) ack 1 win 457 <nop,nop,timestamp 65542739 137784996>
10:52:50.499379 IP 10.246.17.84.65099 > 10.246.17.83.32908: . ack 1449 win 249 <nop,nop,timestamp 137785046 65542739>
10:52:50.499462 IP 10.246.17.83.32908 > 10.246.17.84.65099: . 14481:17377(2896) ack 1 win 457 <nop,nop,timestamp 65542789 137785046>
10:52:50.499381 IP 10.246.17.84.65099 > 10.246.17.83.32908: . ack 2897 win 272 <nop,nop,timestamp 137785046 65542739>
10:52:50.499552 IP 10.246.17.83.32908 > 10.246.17.84.65099: . 17377:20273(2896) ack 1 win 457 <nop,nop,timestamp 65542789 137785046>
10:52:50.499552 IP 10.246.17.84.65099 > 10.246.17.83.32908: . ack 4345 win 295 <nop,nop,timestamp 137785046 65542739>
10:52:50.499661 IP 10.246.17.84.65099 > 10.246.17.83.32908: . ack 5793 win 317 <nop,nop,timestamp 137785046 65542739>
10:52:50.499806 IP 10.246.17.84.65099 > 10.246.17.83.32908: . ack 7241 win 340 <nop,nop,timestamp 137785046 65542739>
10:52:50.499845 IP 10.246.17.83.32908 > 10.246.17.84.65099: . 20273:28961(8688) ack 1 win 457 <nop,nop,timestamp 65542789 137785046>
10:52:50.500006 IP 10.246.17.84.65099 > 10.246.17.83.32908: . ack 8689 win 340 <nop,nop,timestamp 137785047 65542739>

echo 9 >/proc/sys/net/ipv4/tcp_min_tso_segs

10:53:31.504788 IP 10.246.17.83.59687 > 10.246.17.84.38716: S 1238515537:1238515537(0) win 29200 <mss 1460,sackOK,timestamp 65583794 0,nop,wscale 6>
10:53:31.554898 IP 10.246.17.84.38716 > 10.246.17.83.59687: S 667062900:667062900(0) ack 1238515538 win 28960 <mss 1460,sackOK,timestamp 137826102 65583794,nop,wscale 7>
10:53:31.554973 IP 10.246.17.83.59687 > 10.246.17.84.38716: . ack 1 win 457 <nop,nop,timestamp 65583844 137826102>
10:53:31.555050 IP 10.246.17.83.59687 > 10.246.17.84.38716: . 1:13033(13032) ack 1 win 457 <nop,nop,timestamp 65583844 137826102>
10:53:31.555072 IP 10.246.17.83.59687 > 10.246.17.84.38716: . 13033:14481(1448) ack 1 win 457 <nop,nop,timestamp 65583844 137826102>
10:53:31.605154 IP 10.246.17.84.38716 > 10.246.17.83.59687: . ack 1449 win 249 <nop,nop,timestamp 137826152 65583844>
10:53:31.605235 IP 10.246.17.83.59687 > 10.246.17.84.38716: . 14481:17377(2896) ack 1 win 457 <nop,nop,timestamp 65583895 137826152>
10:53:31.605156 IP 10.246.17.84.38716 > 10.246.17.83.59687: . ack 2897 win 272 <nop,nop,timestamp 137826152 65583844>
10:53:31.605293 IP 10.246.17.84.38716 > 10.246.17.83.59687: . ack 4345 win 295 <nop,nop,timestamp 137826152 65583844>
10:53:31.605325 IP 10.246.17.83.59687 > 10.246.17.84.38716: . 17377:23169(5792) ack 1 win 457 <nop,nop,timestamp 65583895 137826152>
10:53:31.605461 IP 10.246.17.84.38716 > 10.246.17.83.59687: . ack 5793 win 317 <nop,nop,timestamp 137826152 65583844>
10:53:31.605599 IP 10.246.17.84.38716 > 10.246.17.83.59687: . ack 7241 win 340 <nop,nop,timestamp 137826152 65583844>
10:53:31.605750 IP 10.246.17.84.38716 > 10.246.17.83.59687: . ack 8689 win 340 <nop,nop,timestamp 137826152 65583844>
10:53:31.605834 IP 10.246.17.83.59687 > 10.246.17.84.38716: . 23169:31857(8688) ack 1 win 457 <nop,nop,timestamp 65583895 137826152>
10:53:31.605899 IP 10.246.17.84.38716 > 10.246.17.83.59687: . ack 10137 win 340 <nop,nop,timestamp 137826153 65583844>
10:53:31.606055 IP 10.246.17.84.38716 > 10.246.17.83.59687: . ack 11585 win 340 <nop,nop,timestamp 137826153 65583844>
10:53:31.606155 IP 10.246.17.83.59687 > 10.246.17.84.38716: . 31857:36201(4344) ack 1 win 457 <nop,nop,timestamp 65583895 137826153>
10:53:31.606157 IP 10.246.17.84.38716 > 10.246.17.83.59687: . ack 13033 win 340 <nop,nop,timestamp 137826153 65583844>

echo 10 >/proc/sys/net/ipv4/tcp_min_tso_segs

10:54:15.974831 IP 10.246.17.83.53733 > 10.246.17.84.34163: S 690526362:690526362(0) win 29200 <mss 1460,sackOK,timestamp 65628264 0,nop,wscale 6>
10:54:16.024978 IP 10.246.17.84.34163 > 10.246.17.83.53733: S 1914393851:1914393851(0) ack 690526363 win 28960 <mss 1460,sackOK,timestamp 137870572 65628264,nop,wscale 7>
10:54:16.025047 IP 10.246.17.83.53733 > 10.246.17.84.34163: . ack 1 win 457 <nop,nop,timestamp 65628314 137870572>
10:54:16.025132 IP 10.246.17.83.53733 > 10.246.17.84.34163: . 1:14481(14480) ack 1 win 457 <nop,nop,timestamp 65628314 137870572>
10:54:16.075247 IP 10.246.17.84.34163 > 10.246.17.83.53733: . ack 1449 win 249 <nop,nop,timestamp 137870622 65628314>
10:54:16.075249 IP 10.246.17.84.34163 > 10.246.17.83.53733: . ack 2897 win 272 <nop,nop,timestamp 137870622 65628314>
10:54:16.075334 IP 10.246.17.83.53733 > 10.246.17.84.34163: . 14481:20273(5792) ack 1 win 457 <nop,nop,timestamp 65628365 137870622>
10:54:16.075452 IP 10.246.17.84.34163 > 10.246.17.83.53733: . ack 4345 win 295 <nop,nop,timestamp 137870622 65628314>
10:54:16.075570 IP 10.246.17.84.34163 > 10.246.17.83.53733: . ack 5793 win 317 <nop,nop,timestamp 137870622 65628314>
10:54:16.075674 IP 10.246.17.84.34163 > 10.246.17.83.53733: . ack 7241 win 340 <nop,nop,timestamp 137870622 65628314>
10:54:16.075698 IP 10.246.17.83.53733 > 10.246.17.84.34163: . 20273:28961(8688) ack 1 win 457 <nop,nop,timestamp 65628365 137870622>
10:54:16.075833 IP 10.246.17.84.34163 > 10.246.17.83.53733: . ack 8689 win 340 <nop,nop,timestamp 137870622 65628314>
10:54:16.075990 IP 10.246.17.84.34163 > 10.246.17.83.53733: . ack 10137 win 340 <nop,nop,timestamp 137870623 65628314>
10:54:16.076116 IP 10.246.17.83.53733 > 10.246.17.84.34163: . 28961:34753(5792) ack 1 win 457 <nop,nop,timestamp 65628365 137870623>
10:54:16.076096 IP 10.246.17.84.34163 > 10.246.17.83.53733: . ack 11585 win 340 <nop,nop,timestamp 137870623 65628314>
10:54:16.076291 IP 10.246.17.84.34163 > 10.246.17.83.53733: . ack 13033 win 340 <nop,nop,timestamp 137870623 65628314>
10:54:16.076435 IP 10.246.17.84.34163 > 10.246.17.83.53733: . ack 14481 win 340 <nop,nop,timestamp 137870623 65628314>
10:54:16.125492 IP 10.246.17.84.34163 > 10.246.17.83.53733: . ack 15929 win 340 <nop,nop,timestamp 137870672 65628365>
10:54:16.125569 IP 10.246.17.83.53733 > 10.246.17.84.34163: . 34753:46337(11584) ack 1 win 457 <nop,nop,timestamp 65628415 137870672>

^ permalink raw reply

* Re: [PATCH] USB2NET : SR9700 : One chip USB 1.1 USB2NET SR9700 Device Driver Support
From: Joe Perches @ 2013-08-24 18:15 UTC (permalink / raw)
  To: liujunliang_ljl
  Cc: davem, horms, romieu, gregkh, netdev, linux-usb, linux-kernel,
	sunhecheng
In-Reply-To: <1377343560-10524-1-git-send-email-liujunliang_ljl@163.com>

Some whitespace and neatening fixups.
Some conversions from 4 indent tabs to normal tabs

Signed-off-by: Joe Perches <joe@perches.com>
---
Just doing this instead of commenting about spacing
again.

 drivers/net/usb/sr9700.c | 127 +++++++++++++++++++++++++----------------------
 1 file changed, 67 insertions(+), 60 deletions(-)

diff --git a/drivers/net/usb/sr9700.c b/drivers/net/usb/sr9700.c
index 27c86ec..4262b9d 100644
--- a/drivers/net/usb/sr9700.c
+++ b/drivers/net/usb/sr9700.c
@@ -29,7 +29,7 @@ static int sr_read(struct usbnet *dev, u8 reg, u16 length, void *data)
 	int err;
 
 	err = usbnet_read_cmd(dev, SR_RD_REGS, SR_REQ_RD_REG,
-					0, reg, data, length);
+			      0, reg, data, length);
 	if ((err != length) && (err >= 0))
 		err = -EINVAL;
 	return err;
@@ -40,7 +40,7 @@ static int sr_write(struct usbnet *dev, u8 reg, u16 length, void *data)
 	int err;
 
 	err = usbnet_write_cmd(dev, SR_WR_REGS, SR_REQ_WR_REG,
-					0, reg, data, length);
+			       0, reg, data, length);
 	if ((err >= 0) && (err < length))
 		err = -EINVAL;
 	return err;
@@ -54,19 +54,19 @@ static int sr_read_reg(struct usbnet *dev, u8 reg, u8 *value)
 static int sr_write_reg(struct usbnet *dev, u8 reg, u8 value)
 {
 	return usbnet_write_cmd(dev, SR_WR_REGS, SR_REQ_WR_REG,
-					value, reg, NULL, 0);
+				value, reg, NULL, 0);
 }
 
 static void sr_write_async(struct usbnet *dev, u8 reg, u16 length, void *data)
 {
 	usbnet_write_cmd_async(dev, SR_WR_REGS, SR_REQ_WR_REG,
-					0, reg, data, length);
+			       0, reg, data, length);
 }
 
 static void sr_write_reg_async(struct usbnet *dev, u8 reg, u8 value)
 {
 	usbnet_write_cmd_async(dev, SR_WR_REGS, SR_REQ_WR_REG,
-					value, reg, NULL, 0);
+			       value, reg, NULL, 0);
 }
 
 static int wait_phy_eeprom_ready(struct usbnet *dev, int phy)
@@ -89,7 +89,7 @@ static int wait_phy_eeprom_ready(struct usbnet *dev, int phy)
 
 	if (i >= SR_SHARE_TIMEOUT) {
 		netdev_err(dev->net, "%s write timed out!\n",
-						phy ? "phy" : "eeprom");
+			   phy ? "phy" : "eeprom");
 		ret = -EIO;
 		goto out;
 	}
@@ -98,7 +98,8 @@ out:
 	return ret;
 }
 
-static int sr_share_read_word(struct usbnet *dev, int phy, u8 reg, __le16 *value)
+static int sr_share_read_word(struct usbnet *dev, int phy, u8 reg,
+			      __le16 *value)
 {
 	int ret;
 
@@ -115,14 +116,15 @@ static int sr_share_read_word(struct usbnet *dev, int phy, u8 reg, __le16 *value
 	ret = sr_read(dev, EPDR, 2, value);
 
 	netdev_dbg(dev->net, "read shared %d 0x%02x returned 0x%04x, %d\n",
-					phy, reg, *value, ret);
+		   phy, reg, *value, ret);
 
 out:
 	mutex_unlock(&dev->phy_mutex);
 	return ret;
 }
 
-static int sr_share_write_word(struct usbnet *dev, int phy, u8 reg, __le16 value)
+static int sr_share_write_word(struct usbnet *dev, int phy, u8 reg,
+			       __le16 value)
 {
 	int ret;
 
@@ -156,7 +158,8 @@ static int sr9700_get_eeprom_len(struct net_device *dev)
 	return SR_EEPROM_LEN;
 }
 
-static int sr9700_get_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom, u8 *data)
+static int sr9700_get_eeprom(struct net_device *net,
+			     struct ethtool_eeprom *eeprom, u8 *data)
 {
 	struct usbnet *dev = netdev_priv(net);
 	__le16 *ebuf = (__le16 *)data;
@@ -168,7 +171,8 @@ static int sr9700_get_eeprom(struct net_device *net, struct ethtool_eeprom *eepr
 		return -EINVAL;
 
 	for (i = 0; i < eeprom->len / 2; i++)
-		ret = sr_read_eeprom_word(dev, eeprom->offset / 2 + i, &ebuf[i]);
+		ret = sr_read_eeprom_word(dev, eeprom->offset / 2 + i,
+					  &ebuf[i]);
 
 	return ret;
 }
@@ -199,12 +203,13 @@ static int sr_mdio_read(struct net_device *netdev, int phy_id, int loc)
 		res = le16_to_cpu(res) & ~BMSR_LSTATUS;
 
 	netdev_dbg(dev->net, "sr_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n",
-					phy_id, loc, res);
+		   phy_id, loc, res);
 
 	return res;
 }
 
-static void sr_mdio_write(struct net_device *netdev, int phy_id, int loc, int val)
+static void sr_mdio_write(struct net_device *netdev, int phy_id, int loc,
+			  int val)
 {
 	struct usbnet *dev = netdev_priv(netdev);
 	__le16 res = cpu_to_le16(val);
@@ -215,7 +220,7 @@ static void sr_mdio_write(struct net_device *netdev, int phy_id, int loc, int va
 	}
 
 	netdev_dbg(dev->net, "sr_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\n",
-					phy_id, loc, val);
+		   phy_id, loc, val);
 
 	sr_share_write_word(dev, 1, loc, res);
 }
@@ -242,15 +247,15 @@ static int sr9700_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
 }
 
 static const struct ethtool_ops sr9700_ethtool_ops = {
-		.get_drvinfo	= usbnet_get_drvinfo,
-		.get_link		= sr9700_get_link,
-		.get_msglevel	= usbnet_get_msglevel,
-		.set_msglevel	= usbnet_set_msglevel,
-		.get_eeprom_len	= sr9700_get_eeprom_len,
-		.get_eeprom		= sr9700_get_eeprom,
-		.get_settings	= usbnet_get_settings,
-		.set_settings	= usbnet_set_settings,
-		.nway_reset		= usbnet_nway_reset,
+	.get_drvinfo	= usbnet_get_drvinfo,
+	.get_link	= sr9700_get_link,
+	.get_msglevel	= usbnet_get_msglevel,
+	.set_msglevel	= usbnet_set_msglevel,
+	.get_eeprom_len	= sr9700_get_eeprom_len,
+	.get_eeprom	= sr9700_get_eeprom,
+	.get_settings	= usbnet_get_settings,
+	.set_settings	= usbnet_set_settings,
+	.nway_reset	= usbnet_nway_reset,
 };
 
 static void sr9700_set_multicast(struct net_device *net)
@@ -269,7 +274,7 @@ static void sr9700_set_multicast(struct net_device *net)
 	if (net->flags & IFF_PROMISC) {
 		rx_ctl |= RCR_PRMSC;
 	} else if (net->flags & IFF_ALLMULTI ||
-			  netdev_mc_count(net) > SR_MCAST_MAX) {
+		   netdev_mc_count(net) > SR_MCAST_MAX) {
 		rx_ctl |= RCR_RUNT;
 	} else if (!netdev_mc_empty(net)) {
 		struct netdev_hw_addr *ha;
@@ -290,7 +295,7 @@ static int sr9700_set_mac_address(struct net_device *net, void *p)
 
 	if (!is_valid_ether_addr(addr->sa_data)) {
 		netdev_err(net, "not setting invalid mac address %pM\n",
-						addr->sa_data);
+			   addr->sa_data);
 		return -EINVAL;
 	}
 
@@ -301,15 +306,15 @@ static int sr9700_set_mac_address(struct net_device *net, void *p)
 }
 
 static const struct net_device_ops sr9700_netdev_ops = {
-		.ndo_open			= usbnet_open,
-		.ndo_stop			= usbnet_stop,
-		.ndo_start_xmit		= usbnet_start_xmit,
-		.ndo_tx_timeout		= usbnet_tx_timeout,
-		.ndo_change_mtu		= usbnet_change_mtu,
-		.ndo_validate_addr	= eth_validate_addr,
-		.ndo_do_ioctl		= sr9700_ioctl,
-		.ndo_set_rx_mode	= sr9700_set_multicast,
-		.ndo_set_mac_address	= sr9700_set_mac_address,
+	.ndo_open		= usbnet_open,
+	.ndo_stop		= usbnet_stop,
+	.ndo_start_xmit		= usbnet_start_xmit,
+	.ndo_tx_timeout		= usbnet_tx_timeout,
+	.ndo_change_mtu		= usbnet_change_mtu,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_do_ioctl		= sr9700_ioctl,
+	.ndo_set_rx_mode	= sr9700_set_multicast,
+	.ndo_set_mac_address	= sr9700_set_mac_address,
 };
 
 static int sr9700_bind(struct usbnet *dev, struct usb_interface *intf)
@@ -360,7 +365,8 @@ static int sr9700_bind(struct usbnet *dev, struct usb_interface *intf)
 
 	sr_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
 	sr_mdio_write(dev->net, dev->mii.phy_id,
-					MII_ADVERTISE, ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
+		      (MII_ADVERTISE, ADVERTISE_ALL |
+		       ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP));
 	mii_nway_restart(&dev->mii);
 
 out:
@@ -373,11 +379,11 @@ static int sr9700_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
 	int len;
 
 	/* skb content (packets) format :
-	 *					p0			p1			p2	......	pm
-	 *			     /	  \
-	 *			/				\
-	 *		/							\
-	 *  /										\
+	 *                    p0            p1            p2    ......    pm
+	 *                 /      \
+	 *            /                \
+	 *        /                            \
+	 *  /                                        \
 	 * p0b0 p0b1 p0b2 p0b3 ...... p0b(n-4) p0b(n-3)...p0bn
 	 *
 	 * p0 : packet 0
@@ -431,7 +437,8 @@ static int sr9700_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
 	return 0;
 }
 
-static struct sk_buff *sr9700_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
+static struct sk_buff *sr9700_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
+				       gfp_t flags)
 {
 	int len;
 
@@ -508,40 +515,40 @@ static int sr9700_link_reset(struct usbnet *dev)
 	mii_ethtool_gset(&dev->mii, &ecmd);
 
 	netdev_dbg(dev->net, "link_reset() speed: %d duplex: %d\n",
-					ecmd.speed, ecmd.duplex);
+		   ecmd.speed, ecmd.duplex);
 
 	return 0;
 }
 
 static const struct driver_info sr9700_driver_info = {
-		.description	= "CoreChip SR9700 USB Ethernet",
-		.flags		= FLAG_ETHER,
-		.bind		= sr9700_bind,
-		.rx_fixup	= sr9700_rx_fixup,
-		.tx_fixup	= sr9700_tx_fixup,
-		.status		= sr9700_status,
-		.link_reset	= sr9700_link_reset,
-		.reset		= sr9700_link_reset,
+	.description	= "CoreChip SR9700 USB Ethernet",
+	.flags		= FLAG_ETHER,
+	.bind		= sr9700_bind,
+	.rx_fixup	= sr9700_rx_fixup,
+	.tx_fixup	= sr9700_tx_fixup,
+	.status		= sr9700_status,
+	.link_reset	= sr9700_link_reset,
+	.reset		= sr9700_link_reset,
 };
 
 static const struct usb_device_id products[] = {
 	{
-	 USB_DEVICE(0x0fe6, 0x9700),	/* SR9700 device */
-	 .driver_info = (unsigned long)&sr9700_driver_info,
-	 },
+		USB_DEVICE(0x0fe6, 0x9700),	/* SR9700 device */
+		.driver_info = (unsigned long)&sr9700_driver_info,
+	},
 	{},			/* END */
 };
 
 MODULE_DEVICE_TABLE(usb, products);
 
 static struct usb_driver sr9700_usb_driver = {
-		.name = "sr9700",
-		.id_table = products,
-		.probe = usbnet_probe,
-		.disconnect = usbnet_disconnect,
-		.suspend = usbnet_suspend,
-		.resume = usbnet_resume,
-		.disable_hub_initiated_lpm = 1,
+	.name		= "sr9700",
+	.id_table	= products,
+	.probe		= usbnet_probe,
+	.disconnect	= usbnet_disconnect,
+	.suspend	= usbnet_suspend,
+	.resume		= usbnet_resume,
+	.disable_hub_initiated_lpm = 1,
 };
 
 module_usb_driver(sr9700_usb_driver);

^ permalink raw reply related

* Re: Understanding/reimplementing forwarding acceleration used by Broadcom (ctf)
From: Kristian Evensen @ 2013-08-24 17:14 UTC (permalink / raw)
  To: OpenWrt Development List; +Cc: Network Development
In-Reply-To: <CACna6rwaa8xkqpt74aDouHjwgqkomYEtpCO3kTX7eVKBPanNzg@mail.gmail.com>

Hi Rafal,

On Sat, Aug 24, 2013 at 5:19 PM, Rafał Miłecki <zajec5@gmail.com> wrote:
>
> I wonder what do you think about this solution. Is this something we
> could try to implement ourself? Is it worth it? Is there some existing
> project doing similar thing?

This is a very interesting discovery. Have you tried to use etables
and checked how much data you can push through the router? For
example, have one machine connected to the LAN and one to the WAN port
(probably using static IPs for the "WAN" is the easiest). Use MAC NAT
(http://ebtables.sourceforge.net/examples/basic.html#ex_nat) on the
OpenWRT router to set the destination to the machine connected to the
WAN, push UDP traffic from a client connected to the LAN to some
remote IP and see how much data flows through the router. Use for
example bwm-ng on the machine connected to the WAN port to see current
throughput (also to avoid putting any additional pressure on the
router CPU). Be aware that unless you configure the machine connected
to the WAN port as a router, the forwarded packets will be discarded.

If this works and gives good performance, based on my understanding,
you could implement this ctf module as an etables extension.

-Kristian
_______________________________________________
openwrt-devel mailing list
openwrt-devel@lists.openwrt.org
https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel

^ permalink raw reply

* Understanding/reimplementing forwarding acceleration used by Broadcom (ctf)
From: Rafał Miłecki @ 2013-08-24 15:19 UTC (permalink / raw)
  To: OpenWrt Development List, Network Development

[-- Attachment #1: Type: text/plain, Size: 2885 bytes --]

Recently I've finally discovered what makes packets forwarding much
faster when using Broadcom's firmware for their routers. It seems
pretty obvious for some DD-WRT guys, but I guess noone of us knew
about it.

It's the magic ctf.ko module that does the trick. It's a closed source
kernel module, that interferences with kernel using simple symbol
exported in setup.c:
ctf_attach_t ctf_attach_fn = NULL;
EXPORT_SYMBOL(ctf_attach_fn);

CTF probably stands for Cut-Through Forwarding.

Removing this module (rmmod ctf) resulted in performance drop on my
WNDR4500 from 505 Mbits/sec to 379 Mbits/sec for LAN to WAN
iperf-tested traffic. My friend tested this on his BCM4706-based
router and removing ctf.ko module resulted in 850Mb/s to 120Mb/s drop.

When ctf.ko gets loaded, it probably just replaces NULL with it's
struct allowing kernel to use it's mysterious API. If you wonder what
part of Linux kernel was modified to make use of ctf.ko, see attached
diff, that's what Broadcom modified in the net tree.

I don't have so good understanding of the net layer, so your help on
that would be more than appreciated.

AFAIK this magic kernel module allows some packets forwarding to be
done directly, with skipping packets analyze in the OS. It means some
features can't be used with it (like QoS), but it still looks like a
nice solution for basic routing.
It looks for me that ctf uses two connections types:
1) brc which may stand for Bridge Connection
2) ipc which may stand for IP Connection

You can see struct ctf_brc and struct ctf_ipc in the attached
hndctf.h. I didn't focus on ctf_brc yet, but I tried to analyze
ctf_ipc. It contains set of data allowing detection of the specific IP
connection. Pretty obviously, it means storing protocol, source (MAC,
IP, port), destination (MAC, IP, port) and few others (like VLAN id,
NAT rules, target interface) values. I guess that ctf.ko analyzes
every received packet using rules stored in struct ctf_ipc. When it
gets some packet covered in it's struct ctf_ipc database, it doesn't
pass it to the OS, but modifies it itself (if needed) and transmits to
the target.
You can see that nf_nat_packet was modified to call
ip_conntrack_ipct_add which tests if the packets matches it's
requirements. If it does, a new IP forwarding rule is added using
ctf_ipc_add.

I wonder what do you think about this solution. Is this something we
could try to implement ourself? Is it worth it? Is there some existing
project doing similar thing?

While ctf.ko module is closed source, it should be possible to
re-implement it. It probably just keeps a list of rules and does some
simple modifications of the received packets (like VLAN id change,
IP/port hacking for SNAT/DNAT), etc.

I don't have any experience in hacking net layer, so any comments on
that would be great!

-- 
Rafał

[-- Attachment #2: hndctf.h --]
[-- Type: text/x-chdr, Size: 10072 bytes --]

/*
 * Copyright (C) 2012, Broadcom Corporation. All Rights Reserved.
 * 
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 * $Id: hndctf.h 371260 2012-11-27 19:42:11Z $
 */

#ifndef _HNDCTF_H_
#define _HNDCTF_H_

#include <bcmutils.h>
#include <proto/bcmip.h>
#include <proto/ethernet.h>
#include <proto/vlan.h>

/*
 * Define to enable couting VLAN tx and rx packets and bytes. This could be
 * disabled if the functionality has impact on performance.
 */
#define CTFVLSTATS

#define CTF_ENAB(ci)		(((ci) != NULL) && (ci)->_ctf)

#define CTF_ACTION_TAG		(1 << 0)
#define CTF_ACTION_UNTAG	(1 << 1)
#define CTF_ACTION_SNAT		(1 << 2)
#define CTF_ACTION_DNAT		(1 << 3)
#define CTF_ACTION_SUSPEND	(1 << 4)
#define CTF_ACTION_TOS		(1 << 5)
#define CTF_ACTION_MARK		(1 << 6)
#define CTF_ACTION_BYTECNT	(1 << 7)
#define CTF_ACTION_PPPOE_ADD	(1 << 8)
#define CTF_ACTION_PPPOE_DEL	(1 << 9)

#define	ctf_attach(osh, n, m, c, a) \
	(ctf_attach_fn ? ctf_attach_fn(osh, n, m, c, a) : NULL)
#define ctf_forward(ci, p, d)	(ci)->fn.forward(ci, p, d)
#define ctf_isenabled(ci, d)	(CTF_ENAB(ci) ? (ci)->fn.isenabled(ci, d) : FALSE)
#define ctf_isbridge(ci, d)	(CTF_ENAB(ci) ? (ci)->fn.isbridge(ci, d) : FALSE)
#define ctf_enable(ci, d, e, b)	(CTF_ENAB(ci) ? (ci)->fn.enable(ci, d, e, b) : BCME_OK)
#define ctf_brc_add(ci, b)	(CTF_ENAB(ci) ? (ci)->fn.brc_add(ci, b) : BCME_OK)
#define ctf_brc_delete(ci, e)	(CTF_ENAB(ci) ? (ci)->fn.brc_delete(ci, e) : BCME_OK)
#define ctf_brc_update(ci, b)	(CTF_ENAB(ci) ? (ci)->fn.brc_update(ci, b) : BCME_OK)
#define ctf_brc_lkup(ci, e)	(CTF_ENAB(ci) ? (ci)->fn.brc_lkup(ci, e) : NULL)
#define ctf_ipc_add(ci, i, v6)	(CTF_ENAB(ci) ? (ci)->fn.ipc_add(ci, i, v6) : BCME_OK)
#define ctf_ipc_delete(ci, i, v6)	\
	(CTF_ENAB(ci) ? (ci)->fn.ipc_delete(ci, i, v6) : BCME_OK)
#define ctf_ipc_count_get(ci, i) \
	(CTF_ENAB(ci) ? (ci)->fn.ipc_count_get(ci, i) : BCME_OK)
#define ctf_ipc_delete_multi(ci, i, im, v6)	\
	(CTF_ENAB(ci) ? (ci)->fn.ipc_delete_multi(ci, i, im, v6) : BCME_OK)
#define ctf_ipc_delete_range(ci, s, e, v6)	\
	(CTF_ENAB(ci) ? (ci)->fn.ipc_delete_range(ci, s, e, v6) : BCME_OK)
#define ctf_ipc_action(ci, s, e, am, v6) \
	(CTF_ENAB(ci) ? (ci)->fn.ipc_action(ci, s, e, am, v6) : BCME_OK)
#define ctf_ipc_lkup(ci, i, v6)	\
	(CTF_ENAB(ci) ? (ci)->fn.ipc_lkup(ci, i, v6) : NULL)
#ifdef CTF_IPV6
#define ctf_ipc_lkup_l4proto(ci, iph, l4p)	(CTF_ENAB(ci) && (ci)->fn.ipc_lkup_l4proto? \
	(ci)->fn.ipc_lkup_l4proto((uint8 *)iph, l4p) : NULL)
#else
#define ctf_ipc_lkup_l4proto(ci, iph, l4p)	(NULL)
#endif /* CTF_IPV6 */
#define ctf_dev_register(ci, d, b)	\
	(CTF_ENAB(ci) ? (ci)->fn.dev_register(ci, d, b) : BCME_OK)
#define ctf_dev_vlan_add(ci, d, vid, vd)	\
	(CTF_ENAB(ci) ? (ci)->fn.dev_vlan_add(ci, d, vid, vd) : BCME_OK)
#define ctf_dev_vlan_delete(ci, d, vid)	\
	(CTF_ENAB(ci) ? (ci)->fn.dev_vlan_delete(ci, d, vid) : BCME_OK)
#define ctf_detach(ci)			if (CTF_ENAB(ci)) (ci)->fn.detach(ci)
#define ctf_dump(ci, b)			if (CTF_ENAB(ci)) (ci)->fn.dump(ci, b)
#define ctf_dev_unregister(ci, d)	if (CTF_ENAB(ci)) (ci)->fn.dev_unregister(ci, d)

#define CTFCNTINCR(s) ((s)++)
#define CTFCNTADD(s, c) ((s) += (c))

#define PPPOE_ETYPE_OFFSET	12
#define PPPOE_VER_OFFSET	14
#define PPPOE_SESID_OFFSET	16
#define PPPOE_LEN_OFFSET	18

#define PPPOE_HLEN		20

#define PPPOE_PROT_PPP		0x0021


typedef struct ctf_pub	ctf_t;
typedef struct ctf_brc	ctf_brc_t;
typedef struct ctf_ipc	ctf_ipc_t;
typedef struct ctf_conn_tuple	ctf_conn_tuple_t;
typedef struct ctf_brc_hot ctf_brc_hot_t;

typedef void (*ctf_detach_cb_t)(ctf_t *ci, void *arg);
typedef ctf_t * (*ctf_attach_t)(osl_t *osh, uint8 *name, uint32 *msg_level,
                                ctf_detach_cb_t cb, void *arg);
typedef void (*ctf_detach_t)(ctf_t *ci);
typedef int32 (*ctf_forward_t)(ctf_t *ci, void *p, void *rxifp);
typedef bool (*ctf_isenabled_t)(ctf_t *ci, void *dev);
typedef bool (*ctf_isbridge_t)(ctf_t *ci, void *dev);
typedef int32 (*ctf_brc_add_t)(ctf_t *ci, ctf_brc_t *brc);
typedef int32 (*ctf_brc_delete_t)(ctf_t *ci, uint8 *ea);
typedef int32 (*ctf_brc_update_t)(ctf_t *ci, ctf_brc_t *brc);
typedef ctf_brc_t * (*ctf_brc_lkup_t)(ctf_t *ci, uint8 *da);
typedef int32 (*ctf_ipc_add_t)(ctf_t *ci, ctf_ipc_t *ipc, bool v6);
typedef int32 (*ctf_ipc_delete_t)(ctf_t *ci, ctf_ipc_t *ipc, bool v6);
typedef int32 (*ctf_ipc_count_get_t)(ctf_t *ci);
typedef int32 (*ctf_ipc_delete_multi_t)(ctf_t *ci, ctf_ipc_t *ipc,
                                        ctf_ipc_t *ipcm, bool v6);
typedef int32 (*ctf_ipc_delete_range_t)(ctf_t *ci, ctf_ipc_t *start,
                                        ctf_ipc_t *end, bool v6);
typedef int32 (*ctf_ipc_action_t)(ctf_t *ci, ctf_ipc_t *start,
                                  ctf_ipc_t *end, uint32 action_mask, bool v6);
typedef ctf_ipc_t * (*ctf_ipc_lkup_t)(ctf_t *ci, ctf_ipc_t *ipc, bool v6);
typedef	uint8 * (*ctf_ipc_lkup_l4proto_t)(uint8 *iph, uint8 *proto_num);
typedef int32 (*ctf_enable_t)(ctf_t *ci, void *dev, bool enable, ctf_brc_hot_t **brc_hot);
typedef int32 (*ctf_dev_register_t)(ctf_t *ci, void *dev, bool br);
typedef void (*ctf_dev_unregister_t)(ctf_t *ci, void *dev);
typedef int32 (*ctf_dev_vlan_add_t)(ctf_t *ci, void *dev, uint16 vid, void *vldev);
typedef int32 (*ctf_dev_vlan_delete_t)(ctf_t *ci, void *dev, uint16 vid);
typedef void (*ctf_dump_t)(ctf_t *ci, struct bcmstrbuf *b);

struct ctf_brc_hot {
	struct ether_addr	ea;	/* Dest address */
	ctf_brc_t		*brcp;	/* BRC entry corresp to dest mac */
};

typedef struct ctf_fn {
	ctf_detach_t		detach;
	ctf_forward_t		forward;
	ctf_isenabled_t		isenabled;
	ctf_isbridge_t		isbridge;
	ctf_brc_add_t		brc_add;
	ctf_brc_delete_t	brc_delete;
	ctf_brc_update_t	brc_update;
	ctf_brc_lkup_t		brc_lkup;
	ctf_ipc_add_t		ipc_add;
	ctf_ipc_delete_t	ipc_delete;
	ctf_ipc_count_get_t	ipc_count_get;
	ctf_ipc_delete_multi_t	ipc_delete_multi;
	ctf_ipc_delete_range_t	ipc_delete_range;
	ctf_ipc_action_t	ipc_action;
	ctf_ipc_lkup_t		ipc_lkup;
	ctf_ipc_lkup_l4proto_t ipc_lkup_l4proto;
	ctf_enable_t		enable;
	ctf_dev_register_t	dev_register;
	ctf_dev_unregister_t	dev_unregister;
	ctf_detach_cb_t		detach_cb;
	void			*detach_cb_arg;
	ctf_dev_vlan_add_t	dev_vlan_add;
	ctf_dev_vlan_delete_t	dev_vlan_delete;
	ctf_dump_t		dump;
} ctf_fn_t;

struct ctf_pub {
	bool			_ctf;		/* Global CTF enable/disable */
	ctf_fn_t		fn;		/* Exported functions */
};

struct ctf_mark;	/* Connection Mark */

struct ctf_brc {
	struct	ctf_brc		*next;		/* Pointer to brc entry */
	struct	ether_addr	dhost;		/* MAC addr of host */
	uint16			vid;		/* VLAN id to use on txif */
	void			*txifp;		/* Interface connected to host */
	uint32			action;		/* Tag or untag the frames */
	uint32			live;		/* Counter used to expire the entry */
	uint32			hits;		/* Num frames matching brc entry */
	uint64			*bytecnt_ptr;	/* Pointer to the byte counter */
};

#ifdef CTF_IPV6
#define IPADDR_U32_SZ		(IPV6_ADDR_LEN / sizeof(uint32))
#else
#define IPADDR_U32_SZ		1
#endif

struct ctf_conn_tuple {
	uint32	sip[IPADDR_U32_SZ], dip[IPADDR_U32_SZ];
	uint16	sp, dp;
	uint8	proto;
};

typedef struct ctf_nat {
	uint32	ip;
	uint16	port;
} ctf_nat_t;

struct ctf_ipc {
	struct	ctf_ipc		*next;		/* Pointer to ipc entry */
	ctf_conn_tuple_t	tuple;		/* Tuple to uniquely id the flow */
	uint16			vid;		/* VLAN id to use on txif */
	struct	ether_addr	dhost;		/* Destination MAC address */
	struct	ether_addr	shost;		/* Source MAC address */
	void			*txif;		/* Target interface to send */
	uint32			action;		/* NAT and/or VLAN actions */
	ctf_brc_t		*brcp;		/* BRC entry corresp to source mac */
	uint32			live;		/* Counter used to expire the entry */
	struct	ctf_nat		nat;		/* Manip data for SNAT, DNAT */
	struct	ether_addr	sa;		/* MAC address of sender */
	uint8			tos;		/* IPv4 tos or IPv6 traffic class field with ECN cleared */
	uint16			pppoe_sid;	/* PPPOE session to use */
	void			*ppp_ifp;	/* PPP interface handle */
	uint32			hits;		/* Num frames matching ipc entry */
	uint64			*bytecnt_ptr;	/* Pointer to the byte counter */
	struct	ctf_mark	mark;		/* Mark value to use for the connection */
};

extern ctf_t *ctf_kattach(osl_t *osh, uint8 *name);
extern void ctf_kdetach(ctf_t *kci);
extern ctf_attach_t ctf_attach_fn;
extern ctf_t *_ctf_attach(osl_t *osh, uint8 *name, uint32 *msg_level,
                          ctf_detach_cb_t cb, void *arg);
extern ctf_t *kcih;

/* Hot bridge cache lkup */
#define MAXBRCHOT		4
#define MAXBRCHOTIF		4
#define CTF_BRC_HOT_HASH(da) 	((((uint8 *)da)[4] ^ ((uint8 *)da)[5]) & (MAXBRCHOT - 1))
#define CTF_HOTBRC_CMP(hbrc, da, rxifp) \
({ \
	ctf_brc_hot_t *bh = (hbrc) + CTF_BRC_HOT_HASH(da); \
	((eacmp((bh)->ea.octet, (da)) == 0) && (bh->brcp->txifp != (rxifp))); \
})

/* Header prep for packets matching hot bridge cache entry */
#define CTF_HOTBRC_L2HDR_PREP(osh, hbrc, prio, data, p) \
do { \
	uint8 *l2h; \
	ctf_brc_hot_t *bh = (hbrc) + CTF_BRC_HOT_HASH(data); \
	ASSERT(*(uint16 *)((data) + VLAN_TPID_OFFSET) == HTON16(ETHER_TYPE_8021Q)); \
	if (bh->brcp->action & CTF_ACTION_UNTAG) { \
		/* Remove vlan header */ \
		l2h = PKTPULL((osh), (p), VLAN_TAG_LEN); \
		ether_rcopy(l2h - VLAN_TAG_LEN + ETHER_ADDR_LEN, \
		            l2h + ETHER_ADDR_LEN); \
		ether_rcopy(l2h - VLAN_TAG_LEN, l2h); \
	} else { \
		/* Update vlan header */ \
		l2h = (data); \
		*(uint16 *)(l2h + VLAN_TCI_OFFSET) = \
		            HTON16((prio) << VLAN_PRI_SHIFT | bh->brcp->vid); \
	} \
} while (0)


#endif /* _HNDCTF_H_ */

[-- Attachment #3: ctf.diff --]
[-- Type: application/octet-stream, Size: 35155 bytes --]

diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h
index 4732432..9856941 100644
--- a/include/net/netfilter/nf_conntrack.h
+++ b/include/net/netfilter/nf_conntrack.h
@@ -46,6 +46,7 @@ union nf_conntrack_expect_proto {
 #include <linux/netfilter/nf_conntrack_pptp.h>
 #include <linux/netfilter/nf_conntrack_h323.h>
 #include <linux/netfilter/nf_conntrack_sane.h>
+#include <linux/netfilter/nf_conntrack_autofw.h>
 
 /* per conntrack: application helper private data */
 union nf_conntrack_help {
@@ -54,6 +55,7 @@ union nf_conntrack_help {
 	struct nf_ct_pptp_master ct_pptp_info;
 	struct nf_ct_h323_master ct_h323_info;
 	struct nf_ct_sane_master ct_sane_info;
+	struct nf_ct_autofw_master ct_autofw_info;
 };
 
 #include <linux/types.h>
@@ -86,6 +88,12 @@ struct nf_conn_help {
 	unsigned int expecting;
 };
 
+#ifdef	HNDCTF
+#define CTF_FLAGS_CACHED	(1 << 31)	/* Indicates cached connection */
+#define CTF_FLAGS_EXCLUDED	(1 << 30)
+#define CTF_FLAGS_REPLY_CACHED	(1 << 1)
+#define CTF_FLAGS_ORG_CACHED	(1 << 0)
+#endif
 
 #include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
 #include <net/netfilter/ipv6/nf_conntrack_ipv6.h>
@@ -96,7 +104,6 @@ struct nf_conn
            plus 1 for any connection(s) we are `master' for */
 	struct nf_conntrack ct_general;
 
-	/* XXX should I move this to the tail ? - Y.K */
 	/* These are my tuples; original and reply */
 	struct nf_conntrack_tuple_hash tuplehash[IP_CT_DIR_MAX];
 
@@ -128,6 +135,14 @@ struct nf_conn
 	u_int32_t secmark;
 #endif
 
+#ifdef HNDCTF
+	/* Timeout for the connection */
+	u_int32_t expire_jiffies;
+
+	/* Flags for connection attributes */
+	u_int32_t ctf_flags;
+#endif /* HNDCTF */
+
 	/* Storage reserved for other modules: */
 	union nf_conntrack_proto proto;
 
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index de78c9d..443285d 100644
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -35,6 +35,9 @@
 #include <linux/if_vlan.h>
 #include "vlan.h"
 #include "vlanproc.h"
+#ifdef HNDCTF
+#include <ctf/hndctf.h>
+#endif /* HNDCTF */
 
 #define DRV_VERSION "1.8"
 
@@ -246,6 +249,9 @@ static int unregister_vlan_dev(struct net_device *real_dev,
 			vlan_group_set_device(grp, vlan_id, NULL);
 			synchronize_net();
 
+#ifdef HNDCTF
+			(void)ctf_dev_vlan_delete(kcih, real_dev, vlan_id);
+#endif /* HNDCTF */
 
 			/* Caller unregisters (and if necessary, puts)
 			 * VLAN device, but we get rid of the reference to
@@ -530,6 +536,10 @@ static struct net_device *register_vlan_device(const char *eth_IF_name,
 	if (register_netdevice(new_dev))
 		goto out_free_newdev;
 
+#ifdef HNDCTF
+	(void)ctf_dev_vlan_add(kcih, real_dev, VLAN_ID, new_dev);
+#endif /* HNDCTF */
+
 	lockdep_set_class(&new_dev->_xmit_lock, &vlan_netdev_xmit_lock_key);
 
 	new_dev->iflink = real_dev->ifindex;
diff --git a/net/8021q/vlanproc.c b/net/8021q/vlanproc.c
index d216a64..f823fc8 100644
--- a/net/8021q/vlanproc.c
+++ b/net/8021q/vlanproc.c
@@ -44,6 +44,9 @@ static void *vlan_seq_start(struct seq_file *seq, loff_t *pos);
 static void *vlan_seq_next(struct seq_file *seq, void *v, loff_t *pos);
 static void vlan_seq_stop(struct seq_file *seq, void *);
 static int vlandev_seq_show(struct seq_file *seq, void *v);
+#ifdef CONFIG_INET_GRO 
+static int gro_write(struct file *file, const char __user *buf, size_t size, loff_t *ppos);
+#endif /* CONFIG_INET_GRO */
 
 /*
  *	Global Data
@@ -98,10 +101,75 @@ static int vlandev_seq_open(struct inode *inode, struct file *file)
 	return single_open(file, vlandev_seq_show, PDE(inode)->data);
 }
 
+#ifdef CONFIG_INET_GRO
+int gro_timer_init;
+struct timer_list gro_timer;
+spinlock_t gro_lock;
+int gro_timer_interval;
+
+static void gro_watchdog(ulong data)
+{
+	struct net_device *gro_dev = (struct net_device *)data;
+	spin_lock_bh(&gro_lock);
+
+	if (gro_dev->features & NETIF_F_GRO) {
+		gro_timer.expires = jiffies + gro_timer_interval;
+		add_timer(&gro_timer);
+	}
+
+	napi_gro_flush(gro_dev);
+
+	spin_unlock_bh(&gro_lock);
+}
+
+static int gro_write(struct file *file, const char __user *buf, size_t size, loff_t *ppos)
+{
+	struct seq_file *seq = (struct seq_file *)file->private_data;
+	struct net_device *gro_dev = seq->private;
+	
+	if (gro_timer_init == 0) {
+		spin_lock_init(&gro_lock);
+		
+		init_timer(&gro_timer);
+		gro_timer.function = gro_watchdog;
+		gro_timer_init = 1;	
+	}
+	
+	if (size < 5 || size > 8)
+		return -EINVAL;
+
+	if (strncmp(buf, "-gro", 4))
+		return -EINVAL;
+
+	sscanf(buf, "-gro %d", &gro_timer_interval);
+
+	if (gro_timer_interval > 0) {
+		gro_dev->features |= NETIF_F_GRO;
+		gro_timer.data = (ulong)gro_dev;
+		gro_timer.expires = jiffies + gro_timer_interval;
+		mod_timer(&gro_timer, jiffies + gro_timer_interval);
+		printk("\ngro enabled with interval %d\n", gro_timer_interval);
+	}
+	else {
+		gro_dev->features &= ~NETIF_F_GRO;
+		del_timer(&gro_timer);
+
+		/* flush packet in gro_device */
+		gro_watchdog((ulong)gro_dev);
+		printk("\ngro disabled\n");
+	}
+
+	return size;
+}
+#endif /* CONFIG_INET_GRO */
+
 static const struct file_operations vlandev_fops = {
 	.owner = THIS_MODULE,
 	.open    = vlandev_seq_open,
 	.read    = seq_read,
+#ifdef CONFIG_INET_GRO
+	.write   = gro_write,
+#endif /* CONFIG_INET_GRO */
 	.llseek  = seq_lseek,
 	.release = single_release,
 };
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
index 3fc6972..14bf114 100644
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -5,7 +5,7 @@
  *	Authors:
  *	Lennert Buytenhek		<buytenh@gnu.org>
  *
- *	$Id: br_fdb.c,v 1.6 2002/01/17 00:57:07 davem Exp $
+ *	$Id: br_fdb.c,v 1.5 2010-06-15 01:09:50 $
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License
@@ -24,6 +24,100 @@
 #include <asm/atomic.h>
 #include <asm/unaligned.h>
 #include "br_private.h"
+#ifdef HNDCTF
+#include <linux/if.h>
+#include <linux/if_vlan.h>
+#include <typedefs.h>
+#include <osl.h>
+#include <ctf/hndctf.h>
+
+static void
+br_brc_init(ctf_brc_t *brc, unsigned char *ea, struct net_device *rxdev)
+{
+	memset(brc, 0, sizeof(ctf_brc_t));
+
+	memcpy(brc->dhost.octet, ea, ETH_ALEN);
+
+        if (rxdev->priv_flags & IFF_802_1Q_VLAN) {
+		brc->txifp = (void *)(VLAN_DEV_INFO(rxdev)->real_dev);
+		brc->vid = VLAN_DEV_INFO(rxdev)->vlan_id;
+		brc->action = ((VLAN_DEV_INFO(rxdev)->flags & 1) ?
+		                     CTF_ACTION_TAG : CTF_ACTION_UNTAG);
+	} else {
+		brc->txifp = (void *)rxdev;
+		brc->action = CTF_ACTION_UNTAG;
+	}
+
+#ifdef DEBUG
+	printk("mac %02x:%02x:%02x:%02x:%02x:%02x\n",
+	       brc->dhost.octet[0], brc->dhost.octet[1],
+	       brc->dhost.octet[2], brc->dhost.octet[3],
+	       brc->dhost.octet[4], brc->dhost.octet[5]);
+	printk("vid: %d action %x\n", brc->vid, brc->action);
+	printk("txif: %s\n", ((struct net_device *)brc->txifp)->name);
+#endif
+
+	return;
+}
+
+/*
+ * Add bridge cache entry.
+ */
+void
+br_brc_add(unsigned char *ea, struct net_device *rxdev)
+{
+	ctf_brc_t brc_entry;
+
+	/* Add brc entry only if packet is received on ctf 
+	 * enabled interface
+	 */
+	if (!ctf_isenabled(kcih, ((rxdev->priv_flags & IFF_802_1Q_VLAN) ?
+	                   VLAN_DEV_INFO(rxdev)->real_dev : rxdev)))
+		return;
+
+	br_brc_init(&brc_entry, ea, rxdev);
+
+#ifdef DEBUG
+	printk("%s: Adding brc entry\n", __FUNCTION__);
+#endif
+
+	/* Add the bridge cache entry */
+	if (ctf_brc_lkup(kcih, ea) == NULL)
+		ctf_brc_add(kcih, &brc_entry);
+	else
+		ctf_brc_update(kcih, &brc_entry);
+
+	return;
+}
+
+/*
+ * Update bridge cache entry.
+ */
+void
+br_brc_update(unsigned char *ea, struct net_device *rxdev)
+{
+	ctf_brc_t brc_entry;
+
+	/* Update brc entry only if packet is received on ctf 
+	 * enabled interface
+	 */
+	if (!ctf_isenabled(kcih, ((rxdev->priv_flags & IFF_802_1Q_VLAN) ?
+	                   VLAN_DEV_INFO(rxdev)->real_dev : rxdev)))
+		return;
+
+	/* Initialize the new device and/or vlan info */
+	br_brc_init(&brc_entry, ea, rxdev);
+
+#ifdef DEBUG
+	printk("%s: Updating brc entry\n", __FUNCTION__);
+#endif
+
+	/* Update the bridge cache entry */
+	ctf_brc_update(kcih, &brc_entry);
+
+	return;
+}
+#endif /* HNDCTF */
 
 static struct kmem_cache *br_fdb_cache __read_mostly;
 static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
@@ -134,9 +228,23 @@ void br_fdb_cleanup(unsigned long _data)
 			if (f->is_static)
 				continue;
 			this_timer = f->ageing_timer + delay;
-			if (time_before_eq(this_timer, jiffies))
+			if (time_before_eq(this_timer, jiffies)) {
+#ifdef HNDCTF
+				ctf_brc_t *brcp;
+
+				/* Before expiring the fdb entry check the brc
+				 * live counter to make sure there are no frames
+				 * on this connection for timeout period.
+				 */
+				brcp = ctf_brc_lkup(kcih, f->addr.addr);
+				if ((brcp != NULL) && (brcp->live > 0)) {
+					brcp->live = 0;
+					f->ageing_timer = jiffies;
+					continue;
+				}
+#endif /* HNDCTF */
 				fdb_delete(f);
-			else if (this_timer < next_timer)
+			} else if (this_timer < next_timer)
 				next_timer = this_timer;
 		}
 	}
@@ -251,8 +359,15 @@ static void fdb_rcu_free(struct rcu_head *head)
 /* Set entry up for deletion with RCU  */
 void br_fdb_put(struct net_bridge_fdb_entry *ent)
 {
-	if (atomic_dec_and_test(&ent->use_count))
+	if (atomic_dec_and_test(&ent->use_count)) {
+#ifdef HNDCTF
+		/* Delete the corresponding brc entry when it expires
+		 * or deleted by user.
+		 */
+		ctf_brc_delete(kcih, ent->addr.addr);
+#endif /* HNDCTF */
 		call_rcu(&ent->rcu, fdb_rcu_free);
+	}
 }
 
 /*
@@ -330,7 +445,14 @@ static struct net_bridge_fdb_entry *fdb_create(struct hlist_head *head,
 		fdb->is_local = is_local;
 		fdb->is_static = is_local;
 		fdb->ageing_timer = jiffies;
+
+		/* Add bridge cache entry for non local hosts */
+#ifdef HNDCTF
+		if (!is_local && (source->state == BR_STATE_FORWARDING))
+			br_brc_add((unsigned char *)addr, source->dev);
+#endif /* HNDCTF */
 	}
+
 	return fdb;
 }
 
@@ -394,6 +516,15 @@ void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source,
 				       source->dev->name);
 		} else {
 			/* fastpath: update of existing entry */
+#ifdef HNDCTF
+			/* Update the brc entry incase the host moved from
+			 * one bridge to another or to a different port under
+			 * the same bridge.
+			 */
+			if (source->state == BR_STATE_FORWARDING)
+				br_brc_update((unsigned char *)addr, source->dev);
+#endif /* HNDCTF */
+
 			fdb->dst = source;
 			fdb->ageing_timer = jiffies;
 		}
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index 849deaf..b589c43 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -5,7 +5,7 @@
  *	Authors:
  *	Lennert Buytenhek		<buytenh@gnu.org>
  *
- *	$Id: br_if.c,v 1.7 2001/12/24 00:59:55 davem Exp $
+ *	$Id: br_if.c,v 1.5 2010-11-04 09:38:03 $
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License
@@ -25,6 +25,10 @@
 
 #include "br_private.h"
 
+#ifdef HNDCTF
+#include <ctf/hndctf.h>
+#endif /* HNDCTF */
+
 /*
  * Determine initial path cost based on speed.
  * using recommendations from 802.1d standard
@@ -217,6 +221,9 @@ static struct net_device *new_bridge_dev(const char *name)
 	br->ageing_time = 300 * HZ;
 	INIT_LIST_HEAD(&br->age_list);
 
+#ifdef CONFIG_INET_GSO
+	br->feature_mask |= NETIF_F_GSO;
+#endif /* CONFIG_INET_GSO */
 	br_stp_timer_init(br);
 
 	return dev;
@@ -286,6 +293,10 @@ int br_add_bridge(const char *name)
 	dev = new_bridge_dev(name);
 	if (!dev)
 		return -ENOMEM;
+		
+#ifdef CONFIG_INET_GSO
+	dev->features |= NETIF_F_GSO;
+#endif /* CONFIG_INET_GSO */
 
 	rtnl_lock();
 	if (strchr(dev->name, '%')) {
@@ -300,6 +311,16 @@ int br_add_bridge(const char *name)
 	if (ret)
 		goto out;
 
+#ifdef HNDCTF
+	if ((ctf_dev_register(kcih, dev, TRUE) != BCME_OK) ||
+	    (ctf_enable(kcih, dev, TRUE, NULL) != BCME_OK)) {
+		ctf_dev_unregister(kcih, dev);
+		unregister_netdevice(dev);
+		ret = -ENXIO;
+		goto out;
+	}
+#endif /* HNDCTF */
+
 	ret = br_sysfs_addbr(dev);
 	if (ret)
 		unregister_netdevice(dev);
@@ -328,8 +349,12 @@ int br_del_bridge(const char *name)
 		ret = -EBUSY;
 	}
 
-	else
+	else {
+#ifdef HNDCTF
+		ctf_dev_unregister(kcih, dev);
+#endif /* HNDCTF */
 		del_br(netdev_priv(dev));
+	}
 
 	rtnl_unlock();
 	return ret;
diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c
index 33c6c4a..36520a2 100644
--- a/net/bridge/br_sysfs_br.c
+++ b/net/bridge/br_sysfs_br.c
@@ -327,6 +327,46 @@ static ssize_t store_flush(struct device *d,
 }
 static DEVICE_ATTR(flush, S_IWUSR, NULL, store_flush);
 
+#ifdef CONFIG_INET_GSO
+static ssize_t show_gso(struct device *d,
+			   struct device_attribute *attr,
+			   const char *buf, size_t len)
+{
+	struct net_bridge *br = to_bridge(d);
+	struct net_device *gso_dev = br->dev;
+
+	if ((br->feature_mask & NETIF_F_GSO) && (gso_dev->features & NETIF_F_GSO))
+		printk("%s: gso on\n", br->dev->name);
+	else
+		printk("%s: gso off\n", br->dev->name);
+	return len;
+}
+
+static ssize_t store_gso(struct device *d,
+				struct device_attribute *attr,
+				const char *buf, size_t len)
+{
+	struct net_bridge *br = to_bridge(d);
+	struct net_device *gso_dev = br->dev;
+
+	if (!strncmp(buf, "on", 2)) {
+		br->feature_mask |= NETIF_F_GSO;
+		gso_dev->features |= NETIF_F_GSO;
+		printk("%s: gso on\n", br->dev->name);
+	}
+	else if (!strncmp(buf, "off", 3)) {
+		br->feature_mask &= ~NETIF_F_GSO;
+		gso_dev->features &= ~NETIF_F_GSO;		
+		printk("%s: gso off\n", br->dev->name);
+	}
+	else
+		printk("%s: invalid argument\n", br->dev->name);
+	
+	return len;
+}
+static DEVICE_ATTR(gso, S_IRUGO | S_IWUSR, show_gso, store_gso);
+#endif /* CONFIG_INET_GSO */
+
 static struct attribute *bridge_attrs[] = {
 	&dev_attr_forward_delay.attr,
 	&dev_attr_hello_time.attr,
@@ -346,6 +386,9 @@ static struct attribute *bridge_attrs[] = {
 	&dev_attr_gc_timer.attr,
 	&dev_attr_group_addr.attr,
 	&dev_attr_flush.attr,
+#ifdef CONFIG_INET_GSO
+	&dev_attr_gso.attr,
+#endif /* CONFIG_INET_GSO */
 	NULL
 };
 
diff --git a/net/ipv4/netfilter/nf_nat_core.c b/net/ipv4/netfilter/nf_nat_core.c
index ea02f00..05e6ee6 100644
--- a/net/ipv4/netfilter/nf_nat_core.c
+++ b/net/ipv4/netfilter/nf_nat_core.c
@@ -31,12 +31,19 @@
 #include <net/netfilter/nf_conntrack_helper.h>
 #include <net/netfilter/nf_conntrack_l3proto.h>
 #include <net/netfilter/nf_conntrack_l4proto.h>
+#include <linux/netfilter_ipv4/ipt_cone.h>
+
+#ifdef HNDCTF
+#include <linux/if.h>
+#include <linux/if_vlan.h>
+#include <typedefs.h>
+#include <osl.h>
+#include <ctf/hndctf.h>
+
+#define NFC_CTF_ENABLED	(1 << 31)
+#endif /* HNDCTF */
 
-#if 0
-#define DEBUGP printk
-#else
 #define DEBUGP(format, args...)
-#endif
 
 static DEFINE_RWLOCK(nf_nat_lock);
 
@@ -87,6 +94,12 @@ hash_by_src(const struct nf_conntrack_tuple *tuple)
 			    tuple->dst.protonum, 0) % nf_nat_htable_size;
 }
 
+#ifdef HNDCTF
+extern void ip_conntrack_ipct_add(struct sk_buff *skb, u_int32_t hooknum,
+	struct nf_conn *ct, enum ip_conntrack_info ci,
+	struct nf_conntrack_tuple *manip);
+#endif /* HNDCTF */
+
 /* Noone using conntrack by the time this called. */
 static void nf_nat_cleanup_conntrack(struct nf_conn *conn)
 {
@@ -98,6 +111,9 @@ static void nf_nat_cleanup_conntrack(struct nf_conn *conn)
 	write_lock_bh(&nf_nat_lock);
 	list_del(&nat->info.bysource);
 	write_unlock_bh(&nf_nat_lock);
+
+	/* Detach from cone list */
+	ipt_cone_cleanup_conntrack(nat);
 }
 
 /* Is this tuple already taken? (not by us) */
@@ -113,6 +129,7 @@ nf_nat_used_tuple(const struct nf_conntrack_tuple *tuple,
 	struct nf_conntrack_tuple reply;
 
 	nf_ct_invert_tuplepr(&reply, tuple);
+
 	return nf_conntrack_tuple_taken(&reply, ignored_conntrack);
 }
 EXPORT_SYMBOL(nf_nat_used_tuple);
@@ -411,10 +428,16 @@ unsigned int nf_nat_packet(struct nf_conn *ct,
 
 		/* We are aiming to look like inverse of other direction. */
 		nf_ct_invert_tuplepr(&target, &ct->tuplehash[!dir].tuple);
-
+#ifdef HNDCTF
+		ip_conntrack_ipct_add(*pskb, hooknum, ct, ctinfo, &target);
+#endif /* HNDCTF */
 		if (!manip_pkt(target.dst.protonum, pskb, 0, &target, mtype))
 			return NF_DROP;
+	} else {
+#ifdef HNDCTF
+#endif /* HNDCTF */
 	}
+
 	return NF_ACCEPT;
 }
 EXPORT_SYMBOL_GPL(nf_nat_packet);
@@ -615,7 +638,6 @@ static int __init nf_nat_init(void)
 		INIT_LIST_HEAD(&bysource[i]);
 	}
 
-	/* FIXME: Man, this is a hack.  <SIGH> */
 	NF_CT_ASSERT(rcu_dereference(nf_conntrack_destroyed) == NULL);
 	rcu_assign_pointer(nf_conntrack_destroyed, nf_nat_cleanup_conntrack);
 
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
index 1b1797f..b51b7d6 100644
--- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
@@ -26,11 +26,7 @@
 #include <net/netfilter/nf_conntrack_l3proto.h>
 #include <net/netfilter/nf_conntrack_core.h>
 
-#if 0
-#define DEBUGP printk
-#else
 #define DEBUGP(format, args...)
-#endif
 
 static int ipv6_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff,
 			     struct nf_conntrack_tuple *tuple)
@@ -230,13 +226,12 @@ static unsigned int ipv6_conntrack_in(unsigned int hooknum,
 				      int (*okfn)(struct sk_buff *))
 {
 	struct sk_buff *reasm = (*pskb)->nfct_reasm;
+	unsigned int ret;
 
 	/* This packet is fragmented and has reassembled packet. */
 	if (reasm) {
 		/* Reassembled packet isn't parsed yet ? */
 		if (!reasm->nfct) {
-			unsigned int ret;
-
 			ret = nf_conntrack_in(PF_INET6, hooknum, &reasm);
 			if (ret != NF_ACCEPT)
 				return ret;
@@ -247,7 +242,19 @@ static unsigned int ipv6_conntrack_in(unsigned int hooknum,
 		return NF_ACCEPT;
 	}
 
-	return nf_conntrack_in(PF_INET6, hooknum, pskb);
+	ret = nf_conntrack_in(PF_INET6, hooknum, pskb);
+
+#if defined(HNDCTF)
+	if (ret == NF_ACCEPT) {
+		struct nf_conn *ct;
+		enum ip_conntrack_info ctinfo;
+
+		ct = nf_ct_get(*pskb, &ctinfo);
+		ip_conntrack_ipct_add(*pskb, hooknum, ct, ctinfo, NULL);
+	}
+#endif /* HNDCTF */
+
+	return ret;
 }
 
 static unsigned int ipv6_conntrack_local(unsigned int hooknum,
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index 7a15e30..70cf589 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -39,11 +39,32 @@
 
 #define NF_CONNTRACK_VERSION	"0.5.0"
 
-#if 0
-#define DEBUGP printk
+#ifdef HNDCTF
+#include <linux/if.h>
+#include <linux/if_vlan.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+
+#ifdef CONFIG_IPV6
+#include <linux/ipv6.h>
+#include <net/ipv6.h>
+#include <net/ip6_route.h>
+#define IPVERSION_IS_4(ipver)		((ipver) == 4)
 #else
+#define IPVERSION_IS_4(ipver)		1
+#endif /* CONFIG_IPV6 */
+
+#include <net/ip.h>
+#include <net/route.h>
+#include <typedefs.h>
+#include <osl.h>
+#include <ctf/hndctf.h>
+
+#define NFC_CTF_ENABLED	(1 << 31)
+#endif /* HNDCTF */
+
 #define DEBUGP(format, args...)
-#endif
 
 DEFINE_RWLOCK(nf_conntrack_lock);
 EXPORT_SYMBOL_GPL(nf_conntrack_lock);
@@ -76,6 +97,348 @@ static unsigned int nf_conntrack_next_id;
 DEFINE_PER_CPU(struct ip_conntrack_stat, nf_conntrack_stat);
 EXPORT_PER_CPU_SYMBOL(nf_conntrack_stat);
 
+#ifdef HNDCTF
+bool
+ip_conntrack_is_ipc_allowed(struct sk_buff *skb, u_int32_t hooknum)
+{
+	struct net_device *dev;
+
+	if (!CTF_ENAB(kcih))
+		return FALSE;
+
+	if (hooknum == NF_IP_PRE_ROUTING || hooknum == NF_IP_POST_ROUTING) {
+		dev = skb->dev;
+		if (dev->priv_flags & IFF_802_1Q_VLAN)
+			dev = VLAN_DEV_INFO(dev)->real_dev;
+
+		/* Add ipc entry if packet is received on ctf enabled interface
+		 * and the packet is not a defrag'd one.
+		 */
+		if (ctf_isenabled(kcih, dev) && (skb->len <= dev->mtu))
+			skb->nfcache |= NFC_CTF_ENABLED;
+	}
+
+	/* Add the cache entries only if the device has registered and
+	 * enabled ctf.
+	 */
+	if (skb->nfcache & NFC_CTF_ENABLED)
+		return TRUE;
+
+	return FALSE;
+}
+
+void
+ip_conntrack_ipct_add(struct sk_buff *skb, u_int32_t hooknum,
+                      struct nf_conn *ct, enum ip_conntrack_info ci,
+                      struct nf_conntrack_tuple *manip)
+{
+	ctf_ipc_t ipc_entry;
+	struct hh_cache *hh;
+	struct ethhdr *eth;
+	struct iphdr *iph;
+	struct tcphdr *tcph;
+	struct rtable *rt;
+	struct nf_conn_help *help;
+	enum ip_conntrack_dir dir;
+	uint8 ipver, protocol;
+#ifdef CONFIG_IPV6
+	struct ipv6hdr *ip6h = NULL;
+#endif /* CONFIG_IPV6 */
+
+	if ((skb == NULL) || (ct == NULL))
+		return;
+
+	/* Check CTF enabled */
+	if (!ip_conntrack_is_ipc_allowed(skb, hooknum))
+		return;
+	/* We only add cache entires for non-helper connections and at
+	 * pre or post routing hooks.
+	 */
+	help = nfct_help(ct);
+	if ((help && help->helper) || (ct->ctf_flags & CTF_FLAGS_EXCLUDED) ||
+	    ((hooknum != NF_IP_PRE_ROUTING) && (hooknum != NF_IP_POST_ROUTING)))
+		return;
+
+	iph = ip_hdr(skb);
+	ipver = iph->version;
+
+	/* Support both IPv4 and IPv6 */
+	if (ipver == 4) {
+		tcph = ((struct tcphdr *)(((__u8 *)iph) + (iph->ihl << 2)));
+		protocol = iph->protocol;
+	}
+#ifdef CONFIG_IPV6
+	else if (ipver == 6) {
+		ip6h = (struct ipv6hdr *)iph;
+		tcph = (struct tcphdr *)ctf_ipc_lkup_l4proto(kcih, ip6h, &protocol);
+		if (tcph == NULL)
+			return;
+	}
+#endif /* CONFIG_IPV6 */
+	else
+		return;
+
+	/* Only TCP and UDP are supported */
+	if (protocol == IPPROTO_TCP) {
+		/* Add ipc entries for connections in established state only */
+		if ((ci != IP_CT_ESTABLISHED) && (ci != (IP_CT_ESTABLISHED+IP_CT_IS_REPLY)))
+			return;
+
+		if (ct->proto.tcp.state >= TCP_CONNTRACK_FIN_WAIT &&
+			ct->proto.tcp.state <= TCP_CONNTRACK_TIME_WAIT)
+			return;
+	}
+	else if (protocol != IPPROTO_UDP)
+		return;
+
+	dir = CTINFO2DIR(ci);
+	if (ct->ctf_flags & (1 << dir))
+		return;
+
+	/* Do route lookup for alias address if we are doing DNAT in this
+	 * direction.
+	 */
+	if (skb->dst == NULL) {
+		/* Find the destination interface */
+		if (IPVERSION_IS_4(ipver)) {
+			u_int32_t daddr;
+
+			if ((manip != NULL) && (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST))
+				daddr = manip->dst.u3.ip;
+			else
+				daddr = iph->daddr;
+			ip_route_input(skb, daddr, iph->saddr, iph->tos, skb->dev);
+		}
+#ifdef CONFIG_IPV6
+		else
+			ip6_route_input(skb);
+#endif /* CONFIG_IPV6 */
+	}
+
+	/* Ensure the packet belongs to a forwarding connection and it is
+	 * destined to an unicast address.
+	 */
+	rt = (struct rtable *)skb->dst;
+	if ((rt == NULL) || (
+#ifdef CONFIG_IPV6
+			!IPVERSION_IS_4(ipver) ?
+			 ((rt->u.dst.input != ip6_forward) ||
+			  !(ipv6_addr_type(&ip6h->daddr) & IPV6_ADDR_UNICAST)) :
+#endif /* CONFIG_IPV6 */
+			 ((rt->u.dst.input != ip_forward) || (rt->rt_type != RTN_UNICAST))) ||
+			(rt->u.dst.neighbour == NULL) ||
+			((rt->u.dst.neighbour->nud_state &
+				(NUD_PERMANENT|NUD_REACHABLE|NUD_STALE|NUD_DELAY|NUD_PROBE)) == 0))
+		return;
+
+	memset(&ipc_entry, 0, sizeof(ipc_entry));
+
+	/* Init the neighboring sender address */
+	memcpy(ipc_entry.sa.octet, eth_hdr(skb)->h_source, ETH_ALEN);
+
+	/* If the packet is received on a bridge device then save
+	 * the bridge cache entry pointer in the ip cache entry.
+	 * This will be referenced in the data path to update the
+	 * live counter of brc entry whenever a received packet
+	 * matches corresponding ipc entry matches.
+	 */
+	if ((skb->dev != NULL) && ctf_isbridge(kcih, skb->dev))
+		ipc_entry.brcp = ctf_brc_lkup(kcih, eth_hdr(skb)->h_source);
+
+	hh = skb->dst->hh;
+	if (hh != NULL) {
+		eth = (struct ethhdr *)(((unsigned char *)hh->hh_data) + 2);
+		memcpy(ipc_entry.dhost.octet, eth->h_dest, ETH_ALEN);
+		memcpy(ipc_entry.shost.octet, eth->h_source, ETH_ALEN);
+	} else {
+		memcpy(ipc_entry.dhost.octet, rt->u.dst.neighbour->ha, ETH_ALEN);
+		memcpy(ipc_entry.shost.octet, skb->dst->dev->dev_addr, ETH_ALEN);
+	}
+
+	/* Add ctf ipc entry for this direction */
+	if (IPVERSION_IS_4(ipver)) {
+		ipc_entry.tuple.sip[0] = iph->saddr;
+		ipc_entry.tuple.dip[0] = iph->daddr;
+#ifdef CONFIG_IPV6
+	}	else {
+		memcpy(ipc_entry.tuple.sip, &ip6h->saddr, sizeof(ipc_entry.tuple.sip));
+		memcpy(ipc_entry.tuple.dip, &ip6h->daddr, sizeof(ipc_entry.tuple.dip));
+#endif /* CONFIG_IPV6 */
+	}
+	ipc_entry.tuple.proto = protocol;
+	ipc_entry.tuple.sp = tcph->source;
+	ipc_entry.tuple.dp = tcph->dest;
+
+	ipc_entry.next = NULL;
+
+	/* For vlan interfaces fill the vlan id and the tag/untag actions */
+	if (skb->dst->dev->priv_flags & IFF_802_1Q_VLAN) {
+		ipc_entry.txif = (void *)(VLAN_DEV_INFO(skb->dst->dev)->real_dev);
+		ipc_entry.vid = VLAN_DEV_INFO(skb->dst->dev)->vlan_id;
+		ipc_entry.action = ((VLAN_DEV_INFO(skb->dst->dev)->flags & 1) ?
+		                    CTF_ACTION_TAG : CTF_ACTION_UNTAG);
+	} else {
+		ipc_entry.txif = skb->dst->dev;
+		ipc_entry.action = CTF_ACTION_UNTAG;
+	}
+
+	/* Update the manip ip and port */
+	if (manip != NULL) {
+		if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC) {
+			ipc_entry.nat.ip = manip->src.u3.ip;
+			ipc_entry.nat.port = manip->src.u.tcp.port;
+			ipc_entry.action |= CTF_ACTION_SNAT;
+		} else {
+			ipc_entry.nat.ip = manip->dst.u3.ip;
+			ipc_entry.nat.port = manip->dst.u.tcp.port;
+			ipc_entry.action |= CTF_ACTION_DNAT;
+		}
+	}
+
+	/* Do bridge cache lookup to determine outgoing interface
+	 * and any vlan tagging actions if needed.
+	 */
+	if (ctf_isbridge(kcih, ipc_entry.txif)) {
+		ctf_brc_t *brcp;
+
+		brcp = ctf_brc_lkup(kcih, ipc_entry.dhost.octet);
+
+		if (brcp == NULL)
+			return;
+		else {
+			ipc_entry.action |= brcp->action;
+			ipc_entry.txif = brcp->txifp;
+			ipc_entry.vid = brcp->vid;
+		}
+	}
+
+#ifdef DEBUG
+	if (IPVERSION_IS_4(ipver))
+		printk("%s: Adding ipc entry for [%d]%u.%u.%u.%u:%u - %u.%u.%u.%u:%u\n", __FUNCTION__,
+			ipc_entry.tuple.proto,
+			NIPQUAD(ipc_entry.tuple.sip[0]), ntohs(ipc_entry.tuple.sp),
+			NIPQUAD(ipc_entry.tuple.dip[0]), ntohs(ipc_entry.tuple.dp));
+#ifdef CONFIG_IPV6
+	else
+		printk("\n%s: Adding ipc entry for [%d]\n"
+			"%08x.%08x.%08x.%08x:%u => %08x.%08x.%08x.%08x:%u\n",
+			__FUNCTION__, ipc_entry.tuple.proto,
+			ntohl(ipc_entry.tuple.sip[0]), ntohl(ipc_entry.tuple.sip[1]),
+			ntohl(ipc_entry.tuple.sip[2]), ntohl(ipc_entry.tuple.sip[3]),
+			ntohs(ipc_entry.tuple.sp),
+			ntohl(ipc_entry.tuple.dip[0]), ntohl(ipc_entry.tuple.dip[1]),
+			ntohl(ipc_entry.tuple.dip[2]), ntohl(ipc_entry.tuple.dip[3]),
+			ntohs(ipc_entry.tuple.dp));
+#endif /* CONFIG_IPV6 */
+	printk("sa %02x:%02x:%02x:%02x:%02x:%02x\n",
+			ipc_entry.shost.octet[0], ipc_entry.shost.octet[1],
+			ipc_entry.shost.octet[2], ipc_entry.shost.octet[3],
+			ipc_entry.shost.octet[4], ipc_entry.shost.octet[5]);
+	printk("da %02x:%02x:%02x:%02x:%02x:%02x\n",
+			ipc_entry.dhost.octet[0], ipc_entry.dhost.octet[1],
+			ipc_entry.dhost.octet[2], ipc_entry.dhost.octet[3],
+			ipc_entry.dhost.octet[4], ipc_entry.dhost.octet[5]);
+	printk("[%d] vid: %d action %x\n", hooknum, ipc_entry.vid, ipc_entry.action);
+	if (manip != NULL)
+		printk("manip_ip: %u.%u.%u.%u manip_port %u\n",
+			NIPQUAD(ipc_entry.nat.ip), ntohs(ipc_entry.nat.port));
+	printk("txif: %s\n", ((struct net_device *)ipc_entry.txif)->name);
+#endif
+
+	ctf_ipc_add(kcih, &ipc_entry, !IPVERSION_IS_4(ipver));
+
+	/* Update the attributes flag to indicate a CTF conn */
+	ct->ctf_flags |= (CTF_FLAGS_CACHED | (1 << dir));
+}
+
+int
+ip_conntrack_ipct_delete(struct nf_conn *ct, int ct_timeout)
+{
+	ctf_ipc_t *ipct;
+	struct nf_conntrack_tuple *orig, *repl;
+	ctf_ipc_t orig_ipct, repl_ipct;
+	int ipaddr_sz;
+	bool v6;
+
+	if (!CTF_ENAB(kcih))
+		return (0);
+
+	orig = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
+
+	if ((orig->dst.protonum != IPPROTO_TCP) && (orig->dst.protonum != IPPROTO_UDP))
+		return (0);
+
+	repl = &ct->tuplehash[IP_CT_DIR_REPLY].tuple;
+
+#ifdef CONFIG_IPV6
+	v6 = (orig->src.l3num == AF_INET6);
+	ipaddr_sz = (v6) ? sizeof(struct in6_addr) : sizeof(struct in_addr);
+#else
+	v6 = FALSE;
+	ipaddr_sz = sizeof(struct in_addr);
+#endif /* CONFIG_IPV6 */
+
+	memset(&orig_ipct, 0, sizeof(orig_ipct));
+	memcpy(orig_ipct.tuple.sip, &orig->src.u3.ip, ipaddr_sz);
+	memcpy(orig_ipct.tuple.dip, &orig->dst.u3.ip, ipaddr_sz);
+	orig_ipct.tuple.proto = orig->dst.protonum;
+	orig_ipct.tuple.sp = orig->src.u.tcp.port;
+	orig_ipct.tuple.dp = orig->dst.u.tcp.port;
+
+	memset(&repl_ipct, 0, sizeof(repl_ipct));
+	memcpy(repl_ipct.tuple.sip, &repl->src.u3.ip, ipaddr_sz);
+	memcpy(repl_ipct.tuple.dip, &repl->dst.u3.ip, ipaddr_sz);
+	repl_ipct.tuple.proto = repl->dst.protonum;
+	repl_ipct.tuple.sp = repl->src.u.tcp.port;
+	repl_ipct.tuple.dp = repl->dst.u.tcp.port;
+
+	/* If the refresh counter of ipc entry is non zero, it indicates
+	 * that the packet transfer is active and we should not delete
+	 * the conntrack entry.
+	 */
+	if (ct_timeout) {
+		ipct = ctf_ipc_lkup(kcih, &orig_ipct, v6);
+
+		/* Postpone the deletion of ct entry if there are frames
+		 * flowing in this direction.
+		 */
+		if ((ipct != NULL) && (ipct->live > 0)) {
+			ipct->live = 0;
+			ct->timeout.expires = jiffies + ct->expire_jiffies;
+			add_timer(&ct->timeout);
+			return (-1);
+		}
+
+		ipct = ctf_ipc_lkup(kcih, &repl_ipct, v6);
+
+		if ((ipct != NULL) && (ipct->live > 0)) {
+			ipct->live = 0;
+			ct->timeout.expires = jiffies + ct->expire_jiffies;
+			add_timer(&ct->timeout);
+			return (-1);
+		}
+	}
+
+	/* If there are no packets over this connection for timeout period
+	 * delete the entries.
+	 */
+	ctf_ipc_delete(kcih, &orig_ipct, v6);
+
+	ctf_ipc_delete(kcih, &repl_ipct, v6);
+
+#ifdef DEBUG
+	printk("%s: Deleting the tuple %x %x %d %d %d\n",
+	       __FUNCTION__, orig->src.u3.ip, orig->dst.u3.ip, orig->dst.protonum,
+	       orig->src.u.tcp.port, orig->dst.u.tcp.port);
+	printk("%s: Deleting the tuple %x %x %d %d %d\n",
+	       __FUNCTION__, repl->dst.u3.ip, repl->src.u3.ip, repl->dst.protonum,
+	       repl->dst.u.tcp.port, repl->src.u.tcp.port);
+#endif
+
+	return (0);
+}
+#endif /* HNDCTF */
+
 /*
  * This scheme offers various size of "struct nf_conn" dependent on
  * features(helper, nat, ...)
@@ -206,7 +569,6 @@ out_up_mutex:
 }
 EXPORT_SYMBOL_GPL(nf_conntrack_register_cache);
 
-/* FIXME: In the current, only nf_conntrack_cleanup() can call this function. */
 void nf_conntrack_unregister_cache(u_int32_t features)
 {
 	struct kmem_cache *cachep;
@@ -272,10 +634,10 @@ nf_ct_invert_tuple(struct nf_conntrack_tuple *inverse,
 {
 	NF_CT_TUPLE_U_BLANK(inverse);
 
-	inverse->src.l3num = orig->src.l3num;
 	if (l3proto->invert_tuple(inverse, orig) == 0)
 		return 0;
 
+	inverse->src.l3num = orig->src.l3num;
 	inverse->dst.dir = !orig->dst.dir;
 
 	inverse->dst.protonum = orig->dst.protonum;
@@ -305,6 +667,10 @@ destroy_conntrack(struct nf_conntrack *nfct)
 	NF_CT_ASSERT(atomic_read(&nfct->use) == 0);
 	NF_CT_ASSERT(!timer_pending(&ct->timeout));
 
+#ifdef HNDCTF
+	ip_conntrack_ipct_delete(ct, 0);
+#endif /* HNDCTF*/
+
 	nf_conntrack_event(IPCT_DESTROY, ct);
 	set_bit(IPS_DYING_BIT, &ct->status);
 
@@ -352,6 +718,14 @@ static void death_by_timeout(unsigned long ul_conntrack)
 	struct nf_conn_help *help = nfct_help(ct);
 	struct nf_conntrack_helper *helper;
 
+#ifdef HNDCTF
+	/* If negative error is returned it means the entry hasn't
+	 * timed out yet.
+	 */
+	if (ip_conntrack_ipct_delete(ct, jiffies >= ct->timeout.expires ? 1 : 0) != 0)
+		return;
+#endif /* HNDCTF */
+
 	if (help) {
 		rcu_read_lock();
 		helper = rcu_dereference(help->helper);
@@ -547,6 +921,10 @@ static int early_drop(struct list_head *chain)
 	if (!ct)
 		return dropped;
 
+#ifdef HNDCTF
+	ip_conntrack_ipct_delete(ct, 0);
+#endif /* HNDCTF */
+
 	if (del_timer(&ct->timeout)) {
 		death_by_timeout((unsigned long)ct);
 		dropped = 1;
@@ -590,7 +968,6 @@ __nf_conntrack_alloc(const struct nf_conntrack_tuple *orig,
 	/*  find features needed by this conntrack. */
 	features |= l3proto->get_features(orig);
 
-	/* FIXME: protect helper list per RCU */
 	read_lock_bh(&nf_conntrack_lock);
 	helper = __nf_ct_helper_find(repl);
 	/* NAT might want to assign a helper later */
@@ -931,6 +1308,9 @@ void __nf_ct_refresh_acct(struct nf_conn *ct,
 
 	/* If not in hash table, timer will not be active yet */
 	if (!nf_ct_is_confirmed(ct)) {
+#ifdef HNDCTF
+		ct->expire_jiffies = extra_jiffies;
+#endif /* HNDCTF */
 		ct->timeout.expires = extra_jiffies;
 		event = IPCT_REFRESH;
 	} else {
@@ -941,6 +1321,9 @@ void __nf_ct_refresh_acct(struct nf_conn *ct,
 		   avoidance (may already be dying). */
 		if (newtime - ct->timeout.expires >= HZ
 		    && del_timer(&ct->timeout)) {
+#ifdef HNDCTF
+			ct->expire_jiffies = extra_jiffies;
+#endif /* HNDCTF */
 			ct->timeout.expires = newtime;
 			add_timer(&ct->timeout);
 			event = IPCT_REFRESH;
@@ -1077,6 +1460,9 @@ nf_ct_iterate_cleanup(int (*iter)(struct nf_conn *i, void *data), void *data)
 	unsigned int bucket = 0;
 
 	while ((ct = get_next_corpse(iter, data, &bucket)) != NULL) {
+#ifdef HNDCTF
+		ip_conntrack_ipct_delete(ct, 0);
+#endif /* HNDCTF */
 		/* Time to push up daises... */
 		if (del_timer(&ct->timeout))
 			death_by_timeout((unsigned long)ct);
diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c
index ccdd5d2..2652fe5 100644
--- a/net/netfilter/nf_conntrack_proto_tcp.c
+++ b/net/netfilter/nf_conntrack_proto_tcp.c
@@ -26,12 +26,12 @@
 #include <net/netfilter/nf_conntrack_l4proto.h>
 #include <net/netfilter/nf_conntrack_ecache.h>
 
-#if 0
-#define DEBUGP printk
-#define DEBUGP_VARS
-#else
 #define DEBUGP(format, args...)
-#endif
+
+#ifdef HNDCTF
+#include <ctf/hndctf.h>
+extern int ip_conntrack_ipct_delete(struct nf_conn *ct, int ct_timeout);
+#endif /* HNDCTF */
 
 /* Protects conntrack->proto.tcp */
 static DEFINE_RWLOCK(tcp_lock);
@@ -50,8 +50,6 @@ static int nf_ct_tcp_loose __read_mostly = 1;
    will be started. */
 static int nf_ct_tcp_max_retrans __read_mostly = 3;
 
-  /* FIXME: Examine ipfilter's timeouts and conntrack transitions more
-     closely.  They're more complex. --RR */
 
 static const char *tcp_conntrack_names[] = {
 	"NONE",
@@ -364,13 +362,10 @@ static inline __u32 segment_seq_plus_len(__u32 seq,
 					 unsigned int dataoff,
 					 struct tcphdr *tcph)
 {
-	/* XXX Should I use payload length field in IP/IPv6 header ?
-	 * - YK */
 	return (seq + len - dataoff - tcph->doff*4
 		+ (tcph->syn ? 1 : 0) + (tcph->fin ? 1 : 0));
 }
 
-/* Fixme: what about big packets? */
 #define MAXACKWINCONST			66000
 #define MAXACKWINDOW(sender)						\
 	((sender)->td_maxwin > MAXACKWINCONST ? (sender)->td_maxwin	\
@@ -792,7 +787,6 @@ static int tcp_error(struct sk_buff *skb,
 	 * We skip checking packets on the outgoing path
 	 * because the checksum is assumed to be correct.
 	 */
-	/* FIXME: Source route IP option packets --RR */
 	if (nf_conntrack_checksum &&
 	    ((pf == PF_INET && hooknum == NF_IP_PRE_ROUTING) ||
 	     (pf == PF_INET6 && hooknum == NF_IP6_PRE_ROUTING)) &&
@@ -933,6 +927,18 @@ static int tcp_packet(struct nf_conn *conntrack,
 		break;
 	}
 
+#ifdef HNDCTF
+	/* Remove the ipc entries on receipt of FIN or RST */
+	if (CTF_ENAB(kcih)) {
+		if (conntrack->ctf_flags & CTF_FLAGS_CACHED) {
+			if (th->fin || th->rst) {
+				ip_conntrack_ipct_delete(conntrack, 0);
+			}
+			goto in_window;
+		}
+	}
+#endif /* HNDCTF */
+
 	if (!tcp_in_window(&conntrack->proto.tcp, dir, index,
 			   skb, dataoff, th, pf)) {
 		write_unlock_bh(&tcp_lock);

[-- Attachment #4: Type: text/plain, Size: 172 bytes --]

_______________________________________________
openwrt-devel mailing list
openwrt-devel@lists.openwrt.org
https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel

^ permalink raw reply related

* Re: [RFC] b44: use phylib
From: Hauke Mehrtens @ 2013-08-24 14:32 UTC (permalink / raw)
  To: Joe Perches; +Cc: zambrano, netdev, Florian Fainelli
In-Reply-To: <1377299409.2816.19.camel@joe-AO722>

On 08/24/2013 01:10 AM, Joe Perches wrote:
> On Sat, 2013-08-24 at 00:56 +0200, Hauke Mehrtens wrote:
>> This splits the driver into the mac and a phy driver. On routers where
>> this driver is used we have a switch which implements a phy and can be
>> controlled by a phy driver.
> 
> trivial comments only...

I will extend this.

>> diff --git a/drivers/net/ethernet/broadcom/b44.c b/drivers/net/ethernet/broadcom/b44.c
> []
>> +static void b44_adjust_link(struct net_device *dev)
>> +{
>> +	struct b44 *bp = netdev_priv(dev);
>> +	struct phy_device *phydev = bp->phydev;
>> +	int status_changed = 0;
> 
> bool?

Thanks, I will change this.

>> +static int b44_mii_probe(struct net_device *dev)
>> +{
> []
>> +	if (IS_ERR(phydev)) {
>> +		netdev_err(dev, "could not attach PHY: %s", phy_id);
> 
> missing newline?

Fixed.

^ permalink raw reply

* [PATCH] USB2NET : SR9700 : One chip USB 1.1 USB2NET SR9700 Device Driver Support
From: liujunliang_ljl-9Onoh4P/yGk @ 2013-08-24 11:26 UTC (permalink / raw)
  To: davem-fT/PcQaiUtIeIZ0/mPfg9Q
  Cc: horms-/R6kz+dDXgpPR4JQBCEnsQ, joe-6d6DIl74uiNBDgjK7y7TUQ,
	romieu-W8zweXLXuWQS+FvcfC7Uqw,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
	netdev-u79uwXL29TY76Z2rM5mHXA, linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	sunhecheng-i49A8sVr+H5BDgjK7y7TUQ, liujl

From: liujl <liujunliang_ljl-9Onoh4P/yGk@public.gmane.org>


Signed-off-by: liujl <liujunliang_ljl-9Onoh4P/yGk@public.gmane.org>
---
 drivers/net/usb/Kconfig  |    8 +
 drivers/net/usb/Makefile |    1 +
 drivers/net/usb/sr9700.c |  551 ++++++++++++++++++++++++++++++++++++++++++++++
 drivers/net/usb/sr9700.h |  172 ++++++++++++++
 4 files changed, 732 insertions(+), 0 deletions(-)
 create mode 100644 drivers/net/usb/sr9700.c
 create mode 100644 drivers/net/usb/sr9700.h

diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig
index 287cc62..a94b196 100644
--- a/drivers/net/usb/Kconfig
+++ b/drivers/net/usb/Kconfig
@@ -272,6 +272,14 @@ config USB_NET_DM9601
 	  This option adds support for Davicom DM9601 based USB 1.1
 	  10/100 Ethernet adapters.
 
+config USB_NET_SR9700
+	tristate "CoreChip-sz SR9700 based USB 1.1 10/100 ethernet devices"
+	depends on USB_USBNET
+	select CRC32
+	help
+	  This option adds support for CoreChip-sz SR9700 based USB 1.1
+	  10/100 Ethernet adapters.
+
 config USB_NET_SMSC75XX
 	tristate "SMSC LAN75XX based USB 2.0 gigabit ethernet devices"
 	depends on USB_USBNET
diff --git a/drivers/net/usb/Makefile b/drivers/net/usb/Makefile
index 9ab5c9d..bba87a2 100644
--- a/drivers/net/usb/Makefile
+++ b/drivers/net/usb/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_USB_NET_AX88179_178A)      += ax88179_178a.o
 obj-$(CONFIG_USB_NET_CDCETHER)	+= cdc_ether.o
 obj-$(CONFIG_USB_NET_CDC_EEM)	+= cdc_eem.o
 obj-$(CONFIG_USB_NET_DM9601)	+= dm9601.o
+obj-$(CONFIG_USB_NET_SR9700)	+= sr9700.o
 obj-$(CONFIG_USB_NET_SMSC75XX)	+= smsc75xx.o
 obj-$(CONFIG_USB_NET_SMSC95XX)	+= smsc95xx.o
 obj-$(CONFIG_USB_NET_GL620A)	+= gl620a.o
diff --git a/drivers/net/usb/sr9700.c b/drivers/net/usb/sr9700.c
new file mode 100644
index 0000000..27c86ec
--- /dev/null
+++ b/drivers/net/usb/sr9700.c
@@ -0,0 +1,551 @@
+/*
+ * CoreChip-sz SR9700 one chip USB 1.1 Ethernet Devices
+ *
+ * Author : liujl <liujunliang_ljl-9Onoh4P/yGk@public.gmane.org>
+ *
+ * Based on dm9601.c
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2.  This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/stddef.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/usb.h>
+#include <linux/crc32.h>
+#include <linux/usb/usbnet.h>
+
+#include "sr9700.h"
+
+static int sr_read(struct usbnet *dev, u8 reg, u16 length, void *data)
+{
+	int err;
+
+	err = usbnet_read_cmd(dev, SR_RD_REGS, SR_REQ_RD_REG,
+					0, reg, data, length);
+	if ((err != length) && (err >= 0))
+		err = -EINVAL;
+	return err;
+}
+
+static int sr_write(struct usbnet *dev, u8 reg, u16 length, void *data)
+{
+	int err;
+
+	err = usbnet_write_cmd(dev, SR_WR_REGS, SR_REQ_WR_REG,
+					0, reg, data, length);
+	if ((err >= 0) && (err < length))
+		err = -EINVAL;
+	return err;
+}
+
+static int sr_read_reg(struct usbnet *dev, u8 reg, u8 *value)
+{
+	return sr_read(dev, reg, 1, value);
+}
+
+static int sr_write_reg(struct usbnet *dev, u8 reg, u8 value)
+{
+	return usbnet_write_cmd(dev, SR_WR_REGS, SR_REQ_WR_REG,
+					value, reg, NULL, 0);
+}
+
+static void sr_write_async(struct usbnet *dev, u8 reg, u16 length, void *data)
+{
+	usbnet_write_cmd_async(dev, SR_WR_REGS, SR_REQ_WR_REG,
+					0, reg, data, length);
+}
+
+static void sr_write_reg_async(struct usbnet *dev, u8 reg, u8 value)
+{
+	usbnet_write_cmd_async(dev, SR_WR_REGS, SR_REQ_WR_REG,
+					value, reg, NULL, 0);
+}
+
+static int wait_phy_eeprom_ready(struct usbnet *dev, int phy)
+{
+	int i, ret;
+
+	ret = 0;
+	for (i = 0; i < SR_SHARE_TIMEOUT; i++) {
+		u8 tmp = 0;
+
+		udelay(1);
+		ret = sr_read_reg(dev, EPCR, &tmp);
+		if (ret < 0)
+			goto out;
+
+		/* ready */
+		if ((tmp & EPCR_ERRE) == 0)
+			break;
+	}
+
+	if (i >= SR_SHARE_TIMEOUT) {
+		netdev_err(dev->net, "%s write timed out!\n",
+						phy ? "phy" : "eeprom");
+		ret = -EIO;
+		goto out;
+	}
+
+out:
+	return ret;
+}
+
+static int sr_share_read_word(struct usbnet *dev, int phy, u8 reg, __le16 *value)
+{
+	int ret;
+
+	mutex_lock(&dev->phy_mutex);
+
+	sr_write_reg(dev, EPAR, phy ? (reg | 0x40) : reg);
+	sr_write_reg(dev, EPCR, phy ? 0xc : 0x4);
+
+	ret = wait_phy_eeprom_ready(dev, phy);
+	if (ret < 0)
+		goto out;
+
+	sr_write_reg(dev, EPCR, 0x0);
+	ret = sr_read(dev, EPDR, 2, value);
+
+	netdev_dbg(dev->net, "read shared %d 0x%02x returned 0x%04x, %d\n",
+					phy, reg, *value, ret);
+
+out:
+	mutex_unlock(&dev->phy_mutex);
+	return ret;
+}
+
+static int sr_share_write_word(struct usbnet *dev, int phy, u8 reg, __le16 value)
+{
+	int ret;
+
+	mutex_lock(&dev->phy_mutex);
+
+	ret = sr_write(dev, EPDR, 2, &value);
+	if (ret < 0)
+		goto out;
+
+	sr_write_reg(dev, EPAR, phy ? (reg | 0x40) : reg);
+	sr_write_reg(dev, EPCR, phy ? 0x1a : 0x12);
+
+	ret = wait_phy_eeprom_ready(dev, phy);
+	if (ret < 0)
+		goto out;
+
+	sr_write_reg(dev, EPCR, 0x0);
+
+out:
+	mutex_unlock(&dev->phy_mutex);
+	return ret;
+}
+
+static int sr_read_eeprom_word(struct usbnet *dev, u8 offset, void *value)
+{
+	return sr_share_read_word(dev, 0, offset, value);
+}
+
+static int sr9700_get_eeprom_len(struct net_device *dev)
+{
+	return SR_EEPROM_LEN;
+}
+
+static int sr9700_get_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom, u8 *data)
+{
+	struct usbnet *dev = netdev_priv(net);
+	__le16 *ebuf = (__le16 *)data;
+	int ret = 0;
+	int i;
+
+	/* access is 16bit */
+	if ((eeprom->offset & 0x01) || (eeprom->len & 0x01))
+		return -EINVAL;
+
+	for (i = 0; i < eeprom->len / 2; i++)
+		ret = sr_read_eeprom_word(dev, eeprom->offset / 2 + i, &ebuf[i]);
+
+	return ret;
+}
+
+static int sr_mdio_read(struct net_device *netdev, int phy_id, int loc)
+{
+	struct usbnet *dev = netdev_priv(netdev);
+	__le16 res;
+	int rc = 0;
+
+	if (phy_id) {
+		netdev_dbg(dev->net, "Only internal phy supported\n");
+		return 0;
+	}
+
+	/* Access NSR_LINKST bit for link status instead of MII_BMSR */
+	if (loc == MII_BMSR) {
+		u8 value;
+
+		sr_read_reg(dev, NSR, &value);
+		if (value & NSR_LINKST)
+			rc = 1;
+	}
+	sr_share_read_word(dev, 1, loc, &res);
+	if (rc == 1)
+		res = le16_to_cpu(res) | BMSR_LSTATUS;
+	else
+		res = le16_to_cpu(res) & ~BMSR_LSTATUS;
+
+	netdev_dbg(dev->net, "sr_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n",
+					phy_id, loc, res);
+
+	return res;
+}
+
+static void sr_mdio_write(struct net_device *netdev, int phy_id, int loc, int val)
+{
+	struct usbnet *dev = netdev_priv(netdev);
+	__le16 res = cpu_to_le16(val);
+
+	if (phy_id) {
+		netdev_dbg(dev->net, "Only internal phy supported\n");
+		return;
+	}
+
+	netdev_dbg(dev->net, "sr_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\n",
+					phy_id, loc, val);
+
+	sr_share_write_word(dev, 1, loc, res);
+}
+
+static u32 sr9700_get_link(struct net_device *net)
+{
+	struct usbnet *dev = netdev_priv(net);
+	u8 value = 0;
+	int rc = 0;
+
+	/* Get the Link Status directly */
+	sr_read_reg(dev, NSR, &value);
+	if (value & NSR_LINKST)
+		rc = 1;
+
+	return rc;
+}
+
+static int sr9700_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
+{
+	struct usbnet *dev = netdev_priv(net);
+
+	return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
+}
+
+static const struct ethtool_ops sr9700_ethtool_ops = {
+		.get_drvinfo	= usbnet_get_drvinfo,
+		.get_link		= sr9700_get_link,
+		.get_msglevel	= usbnet_get_msglevel,
+		.set_msglevel	= usbnet_set_msglevel,
+		.get_eeprom_len	= sr9700_get_eeprom_len,
+		.get_eeprom		= sr9700_get_eeprom,
+		.get_settings	= usbnet_get_settings,
+		.set_settings	= usbnet_set_settings,
+		.nway_reset		= usbnet_nway_reset,
+};
+
+static void sr9700_set_multicast(struct net_device *net)
+{
+	struct usbnet *dev = netdev_priv(net);
+	/* We use the 20 byte dev->data for our 8 byte filter buffer
+	 * to avoid allocating memory that is tricky to free later
+	 */
+	u8 *hashes = (u8 *)&dev->data;
+	/* rx_ctl setting : enable, disable_long, disable_crc */
+	u8 rx_ctl = RCR_RXEN | RCR_DIS_CRC | RCR_DIS_LONG;
+
+	memset(hashes, 0x00, SR_MCAST_SIZE);
+	/* broadcast address */
+	hashes[SR_MCAST_SIZE - 1] |= SR_MCAST_ADDR_FLAG;
+	if (net->flags & IFF_PROMISC) {
+		rx_ctl |= RCR_PRMSC;
+	} else if (net->flags & IFF_ALLMULTI ||
+			  netdev_mc_count(net) > SR_MCAST_MAX) {
+		rx_ctl |= RCR_RUNT;
+	} else if (!netdev_mc_empty(net)) {
+		struct netdev_hw_addr *ha;
+		netdev_for_each_mc_addr(ha, net) {
+			u32 crc = ether_crc(ETH_ALEN, ha->addr) >> 26;
+			hashes[crc >> 3] |= 1 << (crc & 0x7);
+		}
+	}
+
+	sr_write_async(dev, MAR, SR_MCAST_SIZE, hashes);
+	sr_write_reg_async(dev, RCR, rx_ctl);
+}
+
+static int sr9700_set_mac_address(struct net_device *net, void *p)
+{
+	struct usbnet *dev = netdev_priv(net);
+	struct sockaddr *addr = p;
+
+	if (!is_valid_ether_addr(addr->sa_data)) {
+		netdev_err(net, "not setting invalid mac address %pM\n",
+						addr->sa_data);
+		return -EINVAL;
+	}
+
+	memcpy(net->dev_addr, addr->sa_data, net->addr_len);
+	sr_write_async(dev, PAR, 6, dev->net->dev_addr);
+
+	return 0;
+}
+
+static const struct net_device_ops sr9700_netdev_ops = {
+		.ndo_open			= usbnet_open,
+		.ndo_stop			= usbnet_stop,
+		.ndo_start_xmit		= usbnet_start_xmit,
+		.ndo_tx_timeout		= usbnet_tx_timeout,
+		.ndo_change_mtu		= usbnet_change_mtu,
+		.ndo_validate_addr	= eth_validate_addr,
+		.ndo_do_ioctl		= sr9700_ioctl,
+		.ndo_set_rx_mode	= sr9700_set_multicast,
+		.ndo_set_mac_address	= sr9700_set_mac_address,
+};
+
+static int sr9700_bind(struct usbnet *dev, struct usb_interface *intf)
+{
+	int ret;
+
+	ret = usbnet_get_endpoints(dev, intf);
+	if (ret)
+		goto out;
+
+	dev->net->netdev_ops = &sr9700_netdev_ops;
+	dev->net->ethtool_ops = &sr9700_ethtool_ops;
+	dev->net->hard_header_len += SR_TX_OVERHEAD;
+	dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len;
+	/* bulkin buffer is preferably not less than 3K */
+	dev->rx_urb_size = 3072;
+	dev->mii.dev = dev->net;
+	dev->mii.mdio_read = sr_mdio_read;
+	dev->mii.mdio_write = sr_mdio_write;
+	dev->mii.phy_id_mask = 0x1f;
+	dev->mii.reg_num_mask = 0x1f;
+
+	/* reset the sr9700 */
+	sr_write_reg(dev, NCR, 1);
+	udelay(20);
+
+	/* read MAC
+	 * After Chip Power on, the Chip will reload the MAC from
+	 * EEPROM automatically to PAR. In case there is no EEPROM externally,
+	 * a default MAC address is stored in PAR for making chip work properly.
+	 */
+	if (sr_read(dev, PAR, ETH_ALEN, dev->net->dev_addr) < 0) {
+		netdev_err(dev->net, "Error reading MAC address\n");
+		ret = -ENODEV;
+		goto out;
+	}
+
+	/* power up and reset phy */
+	sr_write_reg(dev, PRR, 1);
+	/* at least 10ms, here 20ms for safe */
+	mdelay(20);
+	sr_write_reg(dev, PRR, 0);
+	/* at least 1ms, here 2ms for reading right register */
+	udelay(2 * 1000);
+
+	/* receive broadcast packets */
+	sr9700_set_multicast(dev->net);
+
+	sr_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
+	sr_mdio_write(dev->net, dev->mii.phy_id,
+					MII_ADVERTISE, ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
+	mii_nway_restart(&dev->mii);
+
+out:
+	return ret;
+}
+
+static int sr9700_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
+{
+	struct sk_buff *sr_skb;
+	int len;
+
+	/* skb content (packets) format :
+	 *					p0			p1			p2	......	pm
+	 *			     /	  \
+	 *			/				\
+	 *		/							\
+	 *  /										\
+	 * p0b0 p0b1 p0b2 p0b3 ...... p0b(n-4) p0b(n-3)...p0bn
+	 *
+	 * p0 : packet 0
+	 * p0b0 : packet 0 byte 0
+	 *
+	 * b0: rx status
+	 * b1: packet length (incl crc) low
+	 * b2: packet length (incl crc) high
+	 * b3..n-4: packet data
+	 * bn-3..bn: ethernet packet crc
+	 */
+	if (unlikely(skb->len < SR_RX_OVERHEAD)) {
+		netdev_err(dev->net, "unexpected tiny rx frame\n");
+		return 0;
+	}
+
+	/* one skb may contains multiple packets */
+	while (skb->len > SR_RX_OVERHEAD) {
+		if (skb->data[0] != 0x40)
+			return 0;
+
+		/* ignore the CRC length */
+		len = (skb->data[1] | (skb->data[2] << 8)) - 4;
+
+		if (len > ETH_FRAME_LEN)
+			return 0;
+
+		/* the last packet of current skb */
+		if (skb->len == (len + SR_RX_OVERHEAD))	{
+			skb_pull(skb, 3);
+			skb->len = len;
+			skb->tail = skb->data + len;
+			skb->truesize = len + sizeof(struct sk_buff);
+			return 2;
+		}
+
+		/* skb_clone is used for address align */
+		sr_skb = skb_clone(skb, GFP_ATOMIC);
+		if (!sr_skb)
+			return 0;
+
+		sr_skb->len = len;
+		sr_skb->data = skb->data + 3;
+		sr_skb->tail = skb->data + len;
+		sr_skb->truesize = len + sizeof(struct sk_buff);
+		usbnet_skb_return(dev, sr_skb);
+
+		skb_pull(skb, len + SR_RX_OVERHEAD);
+	};
+
+	return 0;
+}
+
+static struct sk_buff *sr9700_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
+{
+	int len;
+
+	/* SR9700 can only send out one ethernet packet at once.
+	 *
+	 * b0 b1 b2 b3 ...... b(n-4) b(n-3)...bn
+	 *
+	 * b0: rx status
+	 * b1: packet length (incl crc) low
+	 * b2: packet length (incl crc) high
+	 * b3..n-4: packet data
+	 * bn-3..bn: ethernet packet crc
+	 */
+
+	len = skb->len;
+
+	if (skb_headroom(skb) < SR_TX_OVERHEAD) {
+		struct sk_buff *skb2;
+
+		skb2 = skb_copy_expand(skb, SR_TX_OVERHEAD, 0, flags);
+		dev_kfree_skb_any(skb);
+		skb = skb2;
+		if (!skb)
+			return NULL;
+	}
+
+	__skb_push(skb, SR_TX_OVERHEAD);
+
+	/* usbnet adds padding if length is a multiple of packet size
+	 * if so, adjust length value in header
+	 */
+	if ((skb->len % dev->maxpacket) == 0)
+		len++;
+
+	skb->data[0] = len;
+	skb->data[1] = len >> 8;
+
+	return skb;
+}
+
+static void sr9700_status(struct usbnet *dev, struct urb *urb)
+{
+	int link;
+	u8 *buf;
+
+	/* format:
+	   b0: net status
+	   b1: tx status 1
+	   b2: tx status 2
+	   b3: rx status
+	   b4: rx overflow
+	   b5: rx count
+	   b6: tx count
+	   b7: gpr
+	*/
+
+	if (urb->actual_length < 8)
+		return;
+
+	buf = urb->transfer_buffer;
+
+	link = !!(buf[0] & 0x40);
+	if (netif_carrier_ok(dev->net) != link) {
+		usbnet_link_change(dev, link, 1);
+		netdev_dbg(dev->net, "Link Status is: %d\n", link);
+	}
+}
+
+static int sr9700_link_reset(struct usbnet *dev)
+{
+	struct ethtool_cmd ecmd;
+
+	mii_check_media(&dev->mii, 1, 1);
+	mii_ethtool_gset(&dev->mii, &ecmd);
+
+	netdev_dbg(dev->net, "link_reset() speed: %d duplex: %d\n",
+					ecmd.speed, ecmd.duplex);
+
+	return 0;
+}
+
+static const struct driver_info sr9700_driver_info = {
+		.description	= "CoreChip SR9700 USB Ethernet",
+		.flags		= FLAG_ETHER,
+		.bind		= sr9700_bind,
+		.rx_fixup	= sr9700_rx_fixup,
+		.tx_fixup	= sr9700_tx_fixup,
+		.status		= sr9700_status,
+		.link_reset	= sr9700_link_reset,
+		.reset		= sr9700_link_reset,
+};
+
+static const struct usb_device_id products[] = {
+	{
+	 USB_DEVICE(0x0fe6, 0x9700),	/* SR9700 device */
+	 .driver_info = (unsigned long)&sr9700_driver_info,
+	 },
+	{},			/* END */
+};
+
+MODULE_DEVICE_TABLE(usb, products);
+
+static struct usb_driver sr9700_usb_driver = {
+		.name = "sr9700",
+		.id_table = products,
+		.probe = usbnet_probe,
+		.disconnect = usbnet_disconnect,
+		.suspend = usbnet_suspend,
+		.resume = usbnet_resume,
+		.disable_hub_initiated_lpm = 1,
+};
+
+module_usb_driver(sr9700_usb_driver);
+
+MODULE_AUTHOR("liujl <liujunliang_ljl-9Onoh4P/yGk@public.gmane.org>");
+MODULE_DESCRIPTION("SR9700 one chip USB 1.1 USB to Ethernet device from http://www.corechip-sz.com/");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/usb/sr9700.h b/drivers/net/usb/sr9700.h
new file mode 100644
index 0000000..f1968ae
--- /dev/null
+++ b/drivers/net/usb/sr9700.h
@@ -0,0 +1,172 @@
+/*
+ * CoreChip-sz SR9700 one chip USB 1.1 Ethernet Devices
+ *
+ * Author : liujl <liujunliang_ljl-9Onoh4P/yGk@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ */
+
+#ifndef _SR9700_H
+#define	_SR9700_H
+
+/* sr9700 spec. register table on Linux platform */
+
+/* Network Control Reg */
+#define	NCR			0x00
+#define		NCR_RST			(1 << 0)
+#define		NCR_LBK			(3 << 1)
+#define		NCR_FDX			(1 << 3)
+#define		NCR_WAKEEN		(1 << 6)
+/* Network Status Reg */
+#define	NSR			0x01
+#define		NSR_RXRDY		(1 << 0)
+#define		NSR_RXOV		(1 << 1)
+#define		NSR_TX1END		(1 << 2)
+#define		NSR_TX2END		(1 << 3)
+#define		NSR_TXFULL		(1 << 4)
+#define		NSR_WAKEST		(1 << 5)
+#define		NSR_LINKST		(1 << 6)
+#define		NSR_SPEED		(1 << 7)
+/* Tx Control Reg */
+#define	TCR			0x02
+#define		TCR_CRC_DIS		(1 << 1)
+#define		TCR_PAD_DIS		(1 << 2)
+#define		TCR_LC_CARE		(1 << 3)
+#define		TCR_CRS_CARE	(1 << 4)
+#define		TCR_EXCECM		(1 << 5)
+#define		TCR_LF_EN		(1 << 6)
+/* Tx Status Reg for Packet Index 1 */
+#define	TSR1		0x03
+#define		TSR1_EC			(1 << 2)
+#define		TSR1_COL		(1 << 3)
+#define		TSR1_LC			(1 << 4)
+#define		TSR1_NC			(1 << 5)
+#define		TSR1_LOC		(1 << 6)
+#define		TSR1_TLF		(1 << 7)
+/* Tx Status Reg for Packet Index 2 */
+#define	TSR2		0x04
+#define		TSR2_EC			(1 << 2)
+#define		TSR2_COL		(1 << 3)
+#define		TSR2_LC			(1 << 4)
+#define		TSR2_NC			(1 << 5)
+#define		TSR2_LOC		(1 << 6)
+#define		TSR2_TLF		(1 << 7)
+/* Rx Control Reg*/
+#define	RCR			0x05
+#define		RCR_RXEN		(1 << 0)
+#define		RCR_PRMSC		(1 << 1)
+#define		RCR_RUNT		(1 << 2)
+#define		RCR_ALL			(1 << 3)
+#define		RCR_DIS_CRC		(1 << 4)
+#define		RCR_DIS_LONG	(1 << 5)
+/* Rx Status Reg */
+#define	RSR			0x06
+#define		RSR_AE			(1 << 2)
+#define		RSR_MF			(1 << 6)
+#define		RSR_RF			(1 << 7)
+/* Rx Overflow Counter Reg */
+#define	ROCR		0x07
+#define		ROCR_ROC		(0x7F << 0)
+#define		ROCR_RXFU		(1 << 7)
+/* Back Pressure Threshold Reg */
+#define	BPTR		0x08
+#define		BPTR_JPT		(0x0F << 0)
+#define		BPTR_BPHW		(0x0F << 4)
+/* Flow Control Threshold Reg */
+#define	FCTR		0x09
+#define		FCTR_LWOT		(0x0F << 0)
+#define		FCTR_HWOT		(0x0F << 4)
+/* rx/tx Flow Control Reg */
+#define	FCR			0x0A
+#define		FCR_FLCE		(1 << 0)
+#define		FCR_BKPA		(1 << 4)
+#define		FCR_TXPEN		(1 << 5)
+#define		FCR_TXPF		(1 << 6)
+#define		FCR_TXP0		(1 << 7)
+/* Eeprom & Phy Control Reg */
+#define	EPCR		0x0B
+#define		EPCR_ERRE		(1 << 0)
+#define		EPCR_ERPRW		(1 << 1)
+#define		EPCR_ERPRR		(1 << 2)
+#define		EPCR_EPOS		(1 << 3)
+#define		EPCR_WEP		(1 << 4)
+/* Eeprom & Phy Address Reg */
+#define	EPAR		0x0C
+#define		EPAR_EROA		(0x3F << 0)
+#define		EPAR_PHY_ADR	(0x03 << 6)
+/* Eeprom &	Phy Data Reg */
+#define	EPDR		0x0D	/* 0x0D ~ 0x0E for Data Reg Low & High */
+/* Wakeup Control Reg */
+#define	WCR			0x0F
+#define		WCR_MAGICST		(1 << 0)
+#define		WCR_LINKST		(1 << 2)
+#define		WCR_MAGICEN		(1 << 3)
+#define		WCR_LINKEN		(1 << 5)
+/* Physical Address Reg */
+#define	PAR			0x10	/* 0x10 ~ 0x15 6 bytes for PAR */
+/* Multicast Address Reg */
+#define	MAR			0x16	/* 0x16 ~ 0x1D 8 bytes for MAR */
+/* 0x1e unused */
+/* Phy Reset Reg */
+#define	PRR			0x1F
+#define		PRR_PHY_RST		(1 << 0)
+/* Tx sdram Write Pointer Address Low */
+#define	TWPAL		0x20
+/* Tx sdram Write Pointer Address High */
+#define	TWPAH		0x21
+/* Tx sdram Read Pointer Address Low */
+#define	TRPAL		0x22
+/* Tx sdram Read Pointer Address High */
+#define	TRPAH		0x23
+/* Rx sdram Write Pointer Address Low */
+#define	RWPAL		0x24
+/* Rx sdram Write Pointer Address High */
+#define	RWPAH		0x25
+/* Rx sdram Read Pointer Address Low */
+#define	RRPAL		0x26
+/* Rx sdram Read Pointer Address High */
+#define	RRPAH		0x27
+/* Vendor ID register */
+#define	VID			0x28	/* 0x28 ~ 0x29 2 bytes for VID */
+/* Product ID register */
+#define	PID			0x2A	/* 0x2A ~ 0x2B 2 bytes for PID */
+/* CHIP Revision register */
+#define	CHIPR		0x2C
+/* 0x2D --> 0xEF unused */
+/* USB Device Address */
+#define	USBDA		0xF0
+#define		USBDA_USBFA		(0x7F << 0)
+/* RX packet Counter Reg */
+#define	RXC			0xF1
+/* Tx packet Counter & USB Status Reg */
+#define	TXC_USBS	0xF2
+#define		TXC_USBS_TXC0		(1 << 0)
+#define		TXC_USBS_TXC1		(1 << 1)
+#define		TXC_USBS_TXC2		(1 << 2)
+#define		TXC_USBS_EP1RDY		(1 << 5)
+#define		TXC_USBS_SUSFLAG	(1 << 6)
+#define		TXC_USBS_RXFAULT	(1 << 7)
+/* USB Control register */
+#define	USBC		0xF4
+#define		USBC_EP3NAK		(1 << 4)
+#define		USBC_EP3ACK		(1 << 5)
+
+/* Register access commands and flags */
+#define	SR_RD_REGS		0x00
+#define	SR_WR_REGS		0x01
+#define	SR_WR_REG		0x03
+#define	SR_REQ_RD_REG	(USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE)
+#define	SR_REQ_WR_REG	(USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE)
+
+/* parameters */
+#define	SR_SHARE_TIMEOUT	1000
+#define	SR_EEPROM_LEN		256
+#define	SR_MCAST_SIZE		8
+#define	SR_MCAST_ADDR_FLAG	0x80
+#define	SR_MCAST_MAX		64
+#define	SR_TX_OVERHEAD		2	/* 2bytes header */
+#define	SR_RX_OVERHEAD		7	/* 3bytes header + 4crc tail */
+
+#endif	/* _SR9700_H */
-- 
1.7.0.4


--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* Re: [net-next v2 2/8] i40e: transmit, receive, and napi
From: Stefan Assmann @ 2013-08-24  9:31 UTC (permalink / raw)
  To: David Miller
  Cc: jeffrey.t.kirsher, jesse.brandeburg, netdev, gospo,
	shannon.nelson, peter.p.waskiewicz.jr, e1000-devel
In-Reply-To: <20130823.110415.1251655571740007987.davem@davemloft.net>

On 23.08.2013 20:04, David Miller wrote:
> From: Stefan Assmann <sassmann@kpanic.de>
> Date: Fri, 23 Aug 2013 14:42:07 +0200
>
>> On 23.08.2013 04:15, Jeff Kirsher wrote:
>>> From: Jesse Brandeburg <jesse.brandeburg@intel.com>
>>>
>>> This patch contains the transmit, receive, and napi routines, as well
>>> as ancillary routines.
>>>
>>> This file is code that is (will be) shared between the VF and PF
>>> drivers.
>>
>> Just some small nitpicks.
>>
>>> diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c
>>> new file mode 100644
>>> index 0000000..ceafef0
>>> --- /dev/null
>>> +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c
>>
>> [...]
>>
>>> +static void i40e_receive_skb(struct i40e_ring *rx_ring,
>>> +			     struct sk_buff *skb, u16 vlan_tag)
>>> +{
>>> +	struct i40e_vsi *vsi = rx_ring->vsi;
>>> +	struct i40e_q_vector *q_vector = rx_ring->q_vector;
>>> +	u64 flags = vsi->back->flags;
>>> +
>>> +	if (vlan_tag & VLAN_VID_MASK)
>>> +		__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan_tag);
>>
>> Suggesting __constant_htons instead of htons here.
>
> We don't suggest that anymore, because it's completely unnecessary
> with the way the macros are implemented.
>

Okay, good to know. I see it being used frequently in igb, ixgbe so my
assumption was it's the way to go.

   Stefan

^ permalink raw reply

* Re: sendto() bug?
From: Julian Anastasov @ 2013-08-24  8:35 UTC (permalink / raw)
  To: Chris Clark; +Cc: davem, netdev
In-Reply-To: <alpine.DEB.2.02.1308231257140.10771@optio.utah.ind.alcatel.com>


	Hello,

On Fri, 23 Aug 2013, Chris Clark wrote:

> In the same vein as 2ad5b9e4, I'm soliciting feedback on something
> similar for raw_sendmsg():
> 
> =================================================================
> diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
> index dd44e0a..454d9c1 100644
> --- a/net/ipv4/raw.c
> +++ b/net/ipv4/raw.c
> @@ -571,7 +571,9 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
>         flowi4_init_output(&fl4, ipc.oif, sk->sk_mark, tos,
>                            RT_SCOPE_UNIVERSE,
>                            inet->hdrincl ? IPPROTO_RAW : sk->sk_protocol,
> -                          inet_sk_flowi_flags(sk) | FLOWI_FLAG_CAN_SLEEP,
> +                          inet_sk_flowi_flags(sk) | FLOWI_FLAG_CAN_SLEEP
> +                           | ((msg->msg_namelen
> +                               && (tos & RTO_ONLINK)) ? FLOWI_FLAG_KNOWN_NH : 0),
>                            daddr, saddr, 0, 0);
> 
>         if (!inet->hdrincl) {
> =================================================================
> 
> The thought here is to apply the FLOWI_FLAG_KNOWN_NH flag when:
>  (a) The dest_addr is given explicitly (msg->msg_namelen), and
>  (b) The socket is in MSG_DONTROUTE mode (tos & RTO_ONLINK).

	IMHO, FLOWI_FLAG_KNOWN_NH should be set only
for the inet->hdrincl case, otherwise it is set from
routing result: ip_push_pending_frames -> ip_finish_skb ->
__ip_make_skb -> ip_copy_addrs.

	The both cases for hdrincl (usin->sin_addr.s_addr
and inet->inet_daddr) can provide different address, so
it should work also for connected sockets.

	And it should not depend on MSG_DONTROUTE because
daddr for routing and daddr in header can be two
different IPs in local subnet, the user should not
be restricted to use MSG_DONTROUTE just to send
correct ARP request.

	So, something like
(inet->hdrincl ? FLOWI_FLAG_KNOWN_NH : 0) ?

Regards

--
Julian Anastasov <ja@ssi.bg>

^ permalink raw reply

* Warning Alert
From: Hutchinson, Alayna Louise @ 2013-08-24  7:24 UTC (permalink / raw)


IT Service,

You have exceeded the limit of 23432 storage on your mailbox set by your
WEB ITSERVICE/Administrator, and you will be having problems in sending
and receiving mails Until You Re-Validate. You have to update by clicking on the
below link and fill out the information to validate/increase the limit storage of your account.

Please Click the link Below or copy paste to your browser To Validate Your Mailbox

http://webupdatemail.jimdo.com/

Warning!!!
Failure to do this, will result in limited access to your mailbox.
failure to update your account within Three days of this update
notification, your account will be closed permanently.

Sincerely,
IT Service
System Administrator

************************************************************
This is an Administrative Message from IT Service. It is
not spam. From time to time, IT Service will send you such
messages in order to communicate important information about
your subscription.
************************************************************

^ permalink raw reply

* [PATCH] net: stmmac: fixed the pbl setting with DT
From: Byungho An @ 2013-08-24  6:31 UTC (permalink / raw)
  To: netdev
  Cc: 'Giuseppe CAVALLARO', davem,
	'김국진'


This patch fixed the pbl(programmable burst length) setting 
using DT. Even though the default pbl is 8, If there is no 
pbl property in device tree file, pbl is set 0 and it causes 
bandwidth degradation.

Signed-off-by: Byungho An <bh74.an@samsung.com>
---
 .../net/ethernet/stmicro/stmmac/stmmac_platform.c  |   20 ++++++++++++--------
 1 file changed, 12 insertions(+), 8 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
index 98e1988..142ee8e 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
@@ -78,14 +78,18 @@ static int stmmac_probe_config_dt(struct platform_device *pdev,
 		plat->force_sf_dma_mode = 1;
 	}
 
-	dma_cfg = devm_kzalloc(&pdev->dev, sizeof(*dma_cfg), GFP_KERNEL);
-	if (!dma_cfg)
-		return -ENOMEM;
-
-	plat->dma_cfg = dma_cfg;
-	of_property_read_u32(np, "snps,pbl", &dma_cfg->pbl);
-	dma_cfg->fixed_burst = of_property_read_bool(np, "snps,fixed-burst");
-	dma_cfg->mixed_burst = of_property_read_bool(np, "snps,mixed-burst");
+	if (of_find_property(np, "snps,pbl", NULL)) {
+		dma_cfg = devm_kzalloc(&pdev->dev, sizeof(*dma_cfg),
+				       GFP_KERNEL);
+		if (!dma_cfg)
+			return -ENOMEM;
+		plat->dma_cfg = dma_cfg;
+		of_property_read_u32(np, "snps,pbl", &dma_cfg->pbl);
+		dma_cfg->fixed_burst =
+			of_property_read_bool(np, "snps,fixed-burst");
+		dma_cfg->mixed_burst =
+			of_property_read_bool(np, "snps,mixed-burst");
+	}
 
 	return 0;
 }
-- 
1.7.10.4

^ permalink raw reply related

* Re: [PATCH net-next] tcp: TSO packets automatic sizing
From: Neal Cardwell @ 2013-08-24  3:17 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: David Miller, netdev, Yuchung Cheng, Van Jacobson, Tom Herbert
In-Reply-To: <1377304192.8828.43.camel@edumazet-glaptop>

On Fri, Aug 23, 2013 at 8:29 PM, Eric Dumazet <eric.dumazet@gmail.com> wrote:
> From: Eric Dumazet <edumazet@google.com>
>
> After hearing many people over past years complaining against TSO being
> bursty or even buggy, we are proud to present automatic sizing of TSO
> packets.
>
> One part of the problem is that tcp_tso_should_defer() uses an heuristic
> relying on upcoming ACKS instead of a timer, but more generally, having
> big TSO packets makes little sense for low rates, as it tends to create
> micro bursts on the network, and general consensus is to reduce the
> buffering amount.
>
> This patch introduces a per socket sk_pacing_rate, that approximates
> the current sending rate, and allows us to size the TSO packets so
> that we try to send one packet every ms.
>
> This field could be set by other transports.
>
> Patch has no impact for high speed flows, where having large TSO packets
> makes sense to reach line rate.
>
> For other flows, this helps better packet scheduling and ACK clocking.
>
> This patch increases performance of TCP flows in lossy environments.
>
> A new sysctl (tcp_min_tso_segs) is added, to specify the
> minimal size of a TSO packet (default being 2).
>
> A follow-up patch will provide a new packet scheduler (FQ), using
> sk_pacing_rate as an input to perform optional per flow pacing.
>
> This explains why we chose to set sk_pacing_rate to twice the current
> rate, allowing 'slow start' ramp up.
>
> sk_pacing_rate = 2 * cwnd * mss / srtt
>
> Signed-off-by: Eric Dumazet <edumazet@google.com>
> Cc: Neal Cardwell <ncardwell@google.com>
> Cc: Yuchung Cheng <ycheng@google.com>
> Cc: Van Jacobson <vanj@google.com>
> Cc: Tom Herbert <therbert@google.com>
> ---

I love this! Can't wait to play with it.

Rather than implicitly initializing sk_pacing_rate to 0, I'd suggest
maybe initializing sk_pacing_rate to a value just high enough
(TCP_INIT_CWND * mss / 1ms?) so that in the first transmit the
connection can (as it does today) construct a single TSO jumbogram of
TCP_INIT_CWND segments and send that in a single trip down through the
stack. Hopefully this should keep CPU usage advantages of TSO for
servers that spend most of their time sending replies that are 10MSS
or less, while not making the on-the-wire behavior much burstier than
it would be with the patch as it stands.

I am wondering about the aspect of the patch that sets sk_pacing_rate
to 2x the current rate in tcp_rtt_estimator and then just has to
divide by 2 again in tcp_xmit_size_goal(). It seems the 2x factor is
natural in the packet scheduler context, but at first glance it feels
to me like the multiplication by 2 should be an internal detail of the
optional scheduler, not part of the sk_pacing_rate interface between
the TCP and scheduling layer.

One thing I noticed: something about how the current patch shakes out
causes a basic 10-MSS transfer to take an extra RTT, due to the last
2-segment packet having to wait for an ACK:

# cat iw10-base-case.pkt
0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3
0.000 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
0.000 bind(3, ..., ...) = 0
0.000 listen(3, 1) = 0

0.100 < S 0:0(0) win 32792 <mss 1460,sackOK,nop,nop,nop,wscale 7>
0.100 > S. 0:0(0) ack 1 <mss 1460,nop,nop,sackOK,nop,wscale 6>
0.200 < . 1:1(0) ack 1 win 257
0.200 accept(3, ..., ...) = 4

0.200 write(4, ..., 14600) = 14600
0.300 < . 1:1(0) ack 11681 win 257

->

# ./packetdrill iw10-base-case.pkt
0.701287 cli > srv: S 0:0(0) win 32792 <mss 1460,sackOK,nop,nop,nop,wscale 7>
0.701367 srv > cli: S 2822928622:2822928622(0) ack 1 win 29200 <mss
1460,nop,nop,sackOK,nop,wscale 6>
0.801276 cli > srv: . ack 1 win 257
0.801365 srv > cli: . 1:2921(2920) ack 1 win 457
0.801376 srv > cli: . 2921:5841(2920) ack 1 win 457
0.801382 srv > cli: . 5841:8761(2920) ack 1 win 457
0.801386 srv > cli: . 8761:11681(2920) ack 1 win 457
0.901284 cli > srv: . ack 11681 win 257
0.901308 srv > cli: P 11681:14601(2920) ack 1 win 457

I'd try to isolate the exact cause, but it's a bit late in the evening
for me to track this down at this point, and I'll be offline tomorrow.

Thanks again. I love this...

cheers,
neal

^ permalink raw reply

* [PATCH] netfilter: avoid array overflow in nf_register_hook
From: Dong Fang @ 2013-08-24  3:07 UTC (permalink / raw)
  To: pablo, kaber, kadlec, davem, yp.fangdong
  Cc: netfilter-devel, netfilter, coreteam, netdev

This patch fix the array overflow in nf_register_hook function

Signed-off-by: Dong Fang <yp.fangdong@gmail.com>
---
 net/netfilter/core.c |    5 ++++-
 1 files changed, 4 insertions(+), 1 deletions(-)

diff --git a/net/netfilter/core.c b/net/netfilter/core.c
index 2217363..819eee1 100644
--- a/net/netfilter/core.c
+++ b/net/netfilter/core.c
@@ -68,8 +68,11 @@ static DEFINE_MUTEX(nf_hook_mutex);
 int nf_register_hook(struct nf_hook_ops *reg)
 {
 	struct nf_hook_ops *elem;
-	int err;
+	int err = -EINVAL;
 
+	if (reg->pf >= NFPROTO_NUMPROTO || reg->hooknum >= NF_MAX_HOOKS)
+		return err;
+
 	err = mutex_lock_interruptible(&nf_hook_mutex);
 	if (err < 0)
 		return err;
-- 
1.7.1


^ permalink raw reply related

* [PATCH] netfilter: avoid array overflow in nf_register_hook
From: Dong Fang @ 2013-08-24  3:04 UTC (permalink / raw)
  To: pablo, kaber, kadlec, davem
  Cc: netfilter-devel, netfilter, coreteam, netdev, Dong Fang

This patch fix the array overflow in nf_register_hook function

Signed-off-by: Dong Fang <yp.fangdong@gmail.com>
---
 net/netfilter/core.c |    5 ++++-
 1 files changed, 4 insertions(+), 1 deletions(-)

diff --git a/net/netfilter/core.c b/net/netfilter/core.c
index 2217363..819eee1 100644
--- a/net/netfilter/core.c
+++ b/net/netfilter/core.c
@@ -68,8 +68,11 @@ static DEFINE_MUTEX(nf_hook_mutex);
 int nf_register_hook(struct nf_hook_ops *reg)
 {
 	struct nf_hook_ops *elem;
-	int err;
+	int err = -EINVAL;
 
+	if (reg->pf >= NFPROTO_NUMPROTO || reg->hooknum >= NF_MAX_HOOKS)
+		return err;
+
 	err = mutex_lock_interruptible(&nf_hook_mutex);
 	if (err < 0)
 		return err;
-- 
1.7.1


^ permalink raw reply related

* [PATCH net-next] tcp: TSO packets automatic sizing
From: Eric Dumazet @ 2013-08-24  0:29 UTC (permalink / raw)
  To: David Miller
  Cc: netdev, Neal Cardwell, Yuchung Cheng, Van Jacobson, Tom Herbert

From: Eric Dumazet <edumazet@google.com>

After hearing many people over past years complaining against TSO being
bursty or even buggy, we are proud to present automatic sizing of TSO
packets.

One part of the problem is that tcp_tso_should_defer() uses an heuristic
relying on upcoming ACKS instead of a timer, but more generally, having
big TSO packets makes little sense for low rates, as it tends to create
micro bursts on the network, and general consensus is to reduce the
buffering amount.

This patch introduces a per socket sk_pacing_rate, that approximates
the current sending rate, and allows us to size the TSO packets so
that we try to send one packet every ms.

This field could be set by other transports.

Patch has no impact for high speed flows, where having large TSO packets
makes sense to reach line rate.

For other flows, this helps better packet scheduling and ACK clocking.

This patch increases performance of TCP flows in lossy environments.

A new sysctl (tcp_min_tso_segs) is added, to specify the
minimal size of a TSO packet (default being 2).

A follow-up patch will provide a new packet scheduler (FQ), using
sk_pacing_rate as an input to perform optional per flow pacing.

This explains why we chose to set sk_pacing_rate to twice the current
rate, allowing 'slow start' ramp up.

sk_pacing_rate = 2 * cwnd * mss / srtt
 
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Neal Cardwell <ncardwell@google.com>
Cc: Yuchung Cheng <ycheng@google.com>
Cc: Van Jacobson <vanj@google.com>
Cc: Tom Herbert <therbert@google.com>
---
Google-Bug-Id: 8662219

 Documentation/networking/ip-sysctl.txt |    9 +++++++
 include/net/sock.h                     |    2 +
 include/net/tcp.h                      |    1 
 net/ipv4/sysctl_net_ipv4.c             |   10 ++++++++
 net/ipv4/tcp.c                         |   28 ++++++++++++++++++-----
 net/ipv4/tcp_input.c                   |   17 +++++++++++++
 6 files changed, 62 insertions(+), 5 deletions(-)

diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
index debfe85..ce5bb43 100644
--- a/Documentation/networking/ip-sysctl.txt
+++ b/Documentation/networking/ip-sysctl.txt
@@ -482,6 +482,15 @@ tcp_syn_retries - INTEGER
 tcp_timestamps - BOOLEAN
 	Enable timestamps as defined in RFC1323.
 
+tcp_min_tso_segs - INTEGER
+	Minimal number of segments per TCP TSO frame.
+	Since linux-3.12, TCP does an automatic sizing of TSO frames,
+	depending on flow rate, instead of filling 64Kbytes packets.
+	For specific usages, it's possible to force TCP to build big
+	TSO frames. Note that TCP stack might split too big TSO packets
+	if available congestion window is too small.
+	Default: 2
+
 tcp_tso_win_divisor - INTEGER
 	This allows control over what percentage of the congestion window
 	can be consumed by a single TSO frame.
diff --git a/include/net/sock.h b/include/net/sock.h
index e4bbcbf..6ba2e7b 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -232,6 +232,7 @@ struct cg_proto;
   *	@sk_napi_id: id of the last napi context to receive data for sk
   *	@sk_ll_usec: usecs to busypoll when there is no data
   *	@sk_allocation: allocation mode
+  *	@sk_pacing_rate: Pacing rate (if supported by transport/packet scheduler)
   *	@sk_sndbuf: size of send buffer in bytes
   *	@sk_flags: %SO_LINGER (l_onoff), %SO_BROADCAST, %SO_KEEPALIVE,
   *		   %SO_OOBINLINE settings, %SO_TIMESTAMPING settings
@@ -361,6 +362,7 @@ struct sock {
 	kmemcheck_bitfield_end(flags);
 	int			sk_wmem_queued;
 	gfp_t			sk_allocation;
+	u32			sk_pacing_rate; /* bytes per second */
 	netdev_features_t	sk_route_caps;
 	netdev_features_t	sk_route_nocaps;
 	int			sk_gso_type;
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 09cb5c1..73fcd7c 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -281,6 +281,7 @@ extern int sysctl_tcp_early_retrans;
 extern int sysctl_tcp_limit_output_bytes;
 extern int sysctl_tcp_challenge_ack_limit;
 extern unsigned int sysctl_tcp_notsent_lowat;
+extern int sysctl_tcp_min_tso_segs;
 
 extern atomic_long_t tcp_memory_allocated;
 extern struct percpu_counter tcp_sockets_allocated;
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index 8ed7c32..540279f 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -29,6 +29,7 @@
 static int zero;
 static int one = 1;
 static int four = 4;
+static int gso_max_segs = GSO_MAX_SEGS;
 static int tcp_retr1_max = 255;
 static int ip_local_port_range_min[] = { 1, 1 };
 static int ip_local_port_range_max[] = { 65535, 65535 };
@@ -761,6 +762,15 @@ static struct ctl_table ipv4_table[] = {
 		.extra2		= &four,
 	},
 	{
+		.procname	= "tcp_min_tso_segs",
+		.data		= &sysctl_tcp_min_tso_segs,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= proc_dointvec_minmax,
+		.extra1		= &zero,
+		.extra2		= &gso_max_segs,
+	},
+	{
 		.procname	= "udp_mem",
 		.data		= &sysctl_udp_mem,
 		.maxlen		= sizeof(sysctl_udp_mem),
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index ab64eea..e1714ee 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -283,6 +283,8 @@
 
 int sysctl_tcp_fin_timeout __read_mostly = TCP_FIN_TIMEOUT;
 
+int sysctl_tcp_min_tso_segs __read_mostly = 2;
+
 struct percpu_counter tcp_orphan_count;
 EXPORT_SYMBOL_GPL(tcp_orphan_count);
 
@@ -785,12 +787,28 @@ static unsigned int tcp_xmit_size_goal(struct sock *sk, u32 mss_now,
 	xmit_size_goal = mss_now;
 
 	if (large_allowed && sk_can_gso(sk)) {
-		xmit_size_goal = ((sk->sk_gso_max_size - 1) -
-				  inet_csk(sk)->icsk_af_ops->net_header_len -
-				  inet_csk(sk)->icsk_ext_hdr_len -
-				  tp->tcp_header_len);
+		u32 gso_size, hlen;
+
+		/* Maybe we should/could use sk->sk_prot->max_header here ? */
+		hlen = inet_csk(sk)->icsk_af_ops->net_header_len +
+		       inet_csk(sk)->icsk_ext_hdr_len +
+		       tp->tcp_header_len;
+
+		/* Goal is to send at least one packet per ms,
+		 * not one big TSO packet every 100 ms.
+		 * This preserves ACK clocking and is consistent
+		 * with tcp_tso_should_defer() heuristic.
+		 */
+		gso_size = sk->sk_pacing_rate / (2 * MSEC_PER_SEC);
+		gso_size = max_t(u32, gso_size,
+				 sysctl_tcp_min_tso_segs * mss_now);
+
+		xmit_size_goal = min_t(u32, gso_size,
+				       sk->sk_gso_max_size - 1 - hlen);
 
-		/* TSQ : try to have two TSO segments in flight */
+		/* TSQ : try to have at least two segments in flight
+		 * (one in NIC TX ring, another in Qdisc)
+		 */
 		xmit_size_goal = min_t(u32, xmit_size_goal,
 				       sysctl_tcp_limit_output_bytes >> 1);
 
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index ec492ea..0885502 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -629,6 +629,7 @@ static void tcp_rtt_estimator(struct sock *sk, const __u32 mrtt)
 {
 	struct tcp_sock *tp = tcp_sk(sk);
 	long m = mrtt; /* RTT */
+	u64 rate;
 
 	/*	The following amusing code comes from Jacobson's
 	 *	article in SIGCOMM '88.  Note that rtt and mdev
@@ -686,6 +687,22 @@ static void tcp_rtt_estimator(struct sock *sk, const __u32 mrtt)
 		tp->mdev_max = tp->rttvar = max(tp->mdev, tcp_rto_min(sk));
 		tp->rtt_seq = tp->snd_nxt;
 	}
+
+	/* Pacing: -> set sk_pacing_rate to 200 % of current rate */
+	rate = (u64)tp->mss_cache * 8 * 2 * USEC_PER_SEC;
+	rate *= max(tp->snd_cwnd, tp->packets_out);
+
+	do_div(rate, jiffies_to_usecs(tp->srtt));
+	/* Correction for small srtt : minimum srtt being 8 (1 ms),
+	 * be conservative and assume rtt = 125 us instead of 1 ms
+	 * We probably need usec resolution in the future.
+	 */
+	if (tp->srtt <= 8 + 2)
+		rate <<= 3;
+	sk->sk_pacing_rate = min_t(u64, rate, ~0U);
+	pr_debug("cwnd %u packets_out %u srtt %u -> rate = %llu bits\n",
+		 tp->snd_cwnd, tp->packets_out,
+		 jiffies_to_usecs(tp->srtt) >> 3, rate << 3);
 }
 
 /* Calculate rto without backoff.  This is the second half of Van Jacobson's

^ permalink raw reply related

* [net-next] e1000e: balance semaphore put/get for 82573
From: Jeff Kirsher @ 2013-08-24  0:19 UTC (permalink / raw)
  To: davem; +Cc: Steven La, netdev, gospo, sassmann, Jeff Kirsher

From: Steven La <sla@riverbed.com>

Steven (cc-ed) noticed an imbalance in semaphore put/get for
82573-based NICs. Don't we need something like the following
(untested) patch?

Signed-off-by: Steven La <sla@riverbed.com>
Acked-by: Arthur Kepner <akepner@riverbed.com>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
 drivers/net/ethernet/intel/e1000e/82571.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/net/ethernet/intel/e1000e/82571.c b/drivers/net/ethernet/intel/e1000e/82571.c
index 104fcec..8fed74e 100644
--- a/drivers/net/ethernet/intel/e1000e/82571.c
+++ b/drivers/net/ethernet/intel/e1000e/82571.c
@@ -1011,6 +1011,11 @@ static s32 e1000_reset_hw_82571(struct e1000_hw *hw)
 
 	/* Must release MDIO ownership and mutex after MAC reset. */
 	switch (hw->mac.type) {
+	case e1000_82573:
+		/* Release mutex only if the hw semaphore is acquired */
+		if (!ret_val)
+			e1000_put_hw_semaphore_82573(hw);
+		break;
 	case e1000_82574:
 	case e1000_82583:
 		/* Release mutex only if the hw semaphore is acquired */
-- 
1.8.3.1

^ permalink raw reply related

* [net-next v2] Documentation/networking/: Update Intel wired LAN driver documentation
From: Jeff Kirsher @ 2013-08-24  0:19 UTC (permalink / raw)
  To: davem; +Cc: Jeff Kirsher, netdev, gospo, sassmann

Updates the documentation to the Intel wired LAN drivers.

Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Tested-by: Phil Schmitt <phillip.j.schmitt@intel.com>
---
 Documentation/networking/e100.txt    |   4 +-
 Documentation/networking/e1000.txt   |  12 ++--
 Documentation/networking/e1000e.txt  |  16 +++--
 Documentation/networking/igb.txt     |  67 +++++++++++++++++++--
 Documentation/networking/igbvf.txt   |   8 +--
 Documentation/networking/ixgb.txt    |  14 ++---
 Documentation/networking/ixgbe.txt   | 109 +++++++++++++++++++++++++++++++----
 Documentation/networking/ixgbevf.txt |   6 +-
 8 files changed, 193 insertions(+), 43 deletions(-)

diff --git a/Documentation/networking/e100.txt b/Documentation/networking/e100.txt
index fcb6c71c..13a3212 100644
--- a/Documentation/networking/e100.txt
+++ b/Documentation/networking/e100.txt
@@ -1,7 +1,7 @@
 Linux* Base Driver for the Intel(R) PRO/100 Family of Adapters
 ==============================================================
 
-November 15, 2005
+March 15, 2011
 
 Contents
 ========
@@ -122,7 +122,7 @@ Additional Configurations
   NOTE: This setting is not saved across reboots.
 
 
-  Ethtool
+  ethtool
   -------
 
   The driver utilizes the ethtool interface for driver configuration and
diff --git a/Documentation/networking/e1000.txt b/Documentation/networking/e1000.txt
index 71ca958..437b209 100644
--- a/Documentation/networking/e1000.txt
+++ b/Documentation/networking/e1000.txt
@@ -1,8 +1,8 @@
-Linux* Base Driver for the Intel(R) PRO/1000 Family of Adapters
-===============================================================
+Linux* Base Driver for Intel(R) Ethernet Network Connection
+===========================================================
 
 Intel Gigabit Linux driver.
-Copyright(c) 1999 - 2010 Intel Corporation.
+Copyright(c) 1999 - 2013 Intel Corporation.
 
 Contents
 ========
@@ -420,15 +420,15 @@ Additional Configurations
   - The maximum MTU setting for Jumbo Frames is 16110.  This value coincides
     with the maximum Jumbo Frames size of 16128.
 
-  - Using Jumbo Frames at 10 or 100 Mbps may result in poor performance or
-    loss of link.
+  - Using Jumbo frames at 10 or 100 Mbps is not supported and may result in
+    poor performance or loss of link.
 
   - Adapters based on the Intel(R) 82542 and 82573V/E controller do not
     support Jumbo Frames. These correspond to the following product names:
      Intel(R) PRO/1000 Gigabit Server Adapter
      Intel(R) PRO/1000 PM Network Connection
 
-  Ethtool
+  ethtool
   -------
   The driver utilizes the ethtool interface for driver configuration and
   diagnostics, as well as displaying statistical information.  The ethtool
diff --git a/Documentation/networking/e1000e.txt b/Documentation/networking/e1000e.txt
index 97b5ba9..ad2d9f3 100644
--- a/Documentation/networking/e1000e.txt
+++ b/Documentation/networking/e1000e.txt
@@ -1,8 +1,8 @@
-Linux* Driver for Intel(R) Network Connection
-=============================================
+Linux* Driver for Intel(R) Ethernet Network Connection
+======================================================
 
 Intel Gigabit Linux driver.
-Copyright(c) 1999 - 2010 Intel Corporation.
+Copyright(c) 1999 - 2013 Intel Corporation.
 
 Contents
 ========
@@ -259,13 +259,16 @@ Additional Configurations
   - The maximum MTU setting for Jumbo Frames is 9216.  This value coincides
     with the maximum Jumbo Frames size of 9234 bytes.
 
-  - Using Jumbo Frames at 10 or 100 Mbps is not supported and may result in
+  - Using Jumbo frames at 10 or 100 Mbps is not supported and may result in
     poor performance or loss of link.
 
   - Some adapters limit Jumbo Frames sized packets to a maximum of
     4096 bytes and some adapters do not support Jumbo Frames.
 
-  Ethtool
+  - Jumbo Frames cannot be configured on an 82579-based Network device, if
+    MACSec is enabled on the system.
+
+  ethtool
   -------
   The driver utilizes the ethtool interface for driver configuration and
   diagnostics, as well as displaying statistical information.  We
@@ -273,6 +276,9 @@ Additional Configurations
 
   http://ftp.kernel.org/pub/software/network/ethtool/
 
+  NOTE: When validating enable/disable tests on some parts (82578, for example)
+  you need to add a few seconds between tests when working with ethtool.
+
   Speed and Duplex
   ----------------
   Speed and Duplex are configured through the ethtool* utility. For
diff --git a/Documentation/networking/igb.txt b/Documentation/networking/igb.txt
index 9a2a037..4ebbd65 100644
--- a/Documentation/networking/igb.txt
+++ b/Documentation/networking/igb.txt
@@ -1,8 +1,8 @@
-Linux* Base Driver for Intel(R) Network Connection
-==================================================
+Linux* Base Driver for Intel(R) Ethernet Network Connection
+===========================================================
 
 Intel Gigabit Linux driver.
-Copyright(c) 1999 - 2010 Intel Corporation.
+Copyright(c) 1999 - 2013 Intel Corporation.
 
 Contents
 ========
@@ -36,6 +36,53 @@ Default Value: 0
 This parameter adds support for SR-IOV.  It causes the driver to spawn up to
 max_vfs worth of virtual function.
 
+QueuePairs
+----------
+Valid Range:  0-1
+Default Value:  1 (TX and RX will be paired onto one interrupt vector)
+
+If set to 0, when MSI-X is enabled, the TX and RX will attempt to occupy
+separate vectors.
+
+This option can be overridden to 1 if there are not sufficient interrupts
+available.  This can occur if any combination of RSS, VMDQ, and max_vfs
+results in more than 4 queues being used.
+
+Node
+----
+Valid Range:   0-n
+Default Value: -1 (off)
+
+  0 - n: where n is the number of the NUMA node that should be used to
+         allocate memory for this adapter port.
+  -1: uses the driver default of allocating memory on whichever processor is
+      running insmod/modprobe.
+
+  The Node parameter will allow you to pick which NUMA node you want to have
+  the adapter allocate memory from.  All driver structures, in-memory queues,
+  and receive buffers will be allocated on the node specified.  This parameter
+  is only useful when interrupt affinity is specified, otherwise some portion
+  of the time the interrupt could run on a different core than the memory is
+  allocated on, causing slower memory access and impacting throughput, CPU, or
+  both.
+
+EEE
+---
+Valid Range:  0-1
+Default Value: 1 (enabled)
+
+  A link between two EEE-compliant devices will result in periodic bursts of
+  data followed by long periods where in the link is in an idle state. This Low
+  Power Idle (LPI) state is supported in both 1Gbps and 100Mbps link speeds.
+  NOTE: EEE support requires autonegotiation.
+
+DMAC
+----
+Valid Range: 0-1
+Default Value: 1 (enabled)
+  Enables or disables DMA Coalescing feature.
+
+
 
 Additional Configurations
 =========================
@@ -55,10 +102,10 @@ Additional Configurations
   - The maximum MTU setting for Jumbo Frames is 9216.  This value coincides
     with the maximum Jumbo Frames size of 9234 bytes.
 
-  - Using Jumbo Frames at 10 or 100 Mbps may result in poor performance or
-    loss of link.
+  - Using Jumbo frames at 10 or 100 Mbps is not supported and may result in
+    poor performance or loss of link.
 
-  Ethtool
+  ethtool
   -------
   The driver utilizes the ethtool interface for driver configuration and
   diagnostics, as well as displaying statistical information. The latest
@@ -106,6 +153,14 @@ Additional Configurations
 
   Where n=the VF that attempted to do the spoofing.
 
+  Setting MAC Address, VLAN and Rate Limit Using IProute2 Tool
+  ------------------------------------------------------------
+  You can set a MAC address of a Virtual Function (VF), a default VLAN and the
+  rate limit using the IProute2 tool. Download the latest version of the
+  iproute2 tool from Sourceforge if your version does not have all the
+  features you require.
+
+
 Support
 =======
 
diff --git a/Documentation/networking/igbvf.txt b/Documentation/networking/igbvf.txt
index cbfe4ee..40db17a 100644
--- a/Documentation/networking/igbvf.txt
+++ b/Documentation/networking/igbvf.txt
@@ -1,8 +1,8 @@
-Linux* Base Driver for Intel(R) Network Connection
-==================================================
+Linux* Base Driver for Intel(R) Ethernet Network Connection
+===========================================================
 
 Intel Gigabit Linux driver.
-Copyright(c) 1999 - 2010 Intel Corporation.
+Copyright(c) 1999 - 2013 Intel Corporation.
 
 Contents
 ========
@@ -55,7 +55,7 @@ networking link on the left to search for your adapter:
 Additional Configurations
 =========================
 
-  Ethtool
+  ethtool
   -------
   The driver utilizes the ethtool interface for driver configuration and
   diagnostics, as well as displaying statistical information.  The ethtool
diff --git a/Documentation/networking/ixgb.txt b/Documentation/networking/ixgb.txt
index d75a1f9..1e0c045 100644
--- a/Documentation/networking/ixgb.txt
+++ b/Documentation/networking/ixgb.txt
@@ -1,7 +1,7 @@
-Linux Base Driver for 10 Gigabit Intel(R) Network Connection
-=============================================================
+Linux Base Driver for 10 Gigabit Intel(R) Ethernet Network Connection
+=====================================================================
 
-October 9, 2007
+March 14, 2011
 
 
 Contents
@@ -274,9 +274,9 @@ Additional Configurations
   -------------------------------------------------
   Configuring a network driver to load properly when the system is started is
   distribution dependent. Typically, the configuration process involves adding
-  an alias line to files in /etc/modprobe.d/ as well as editing other system
-  startup scripts and/or configuration files.  Many popular Linux distributions
-  ship with tools to make these changes for you.  To learn the proper way to
+  an alias line to /etc/modprobe.conf as well as editing other system startup
+  scripts and/or configuration files.  Many popular Linux distributions ship
+  with tools to make these changes for you.  To learn the proper way to
   configure a network device for your system, refer to your distribution
   documentation.  If during this process you are asked for the driver or module
   name, the name for the Linux Base Driver for the Intel 10GbE Family of
@@ -306,7 +306,7 @@ Additional Configurations
   with the maximum Jumbo Frames size of 16128.
 
 
-  Ethtool
+  ethtool
   -------
   The driver utilizes the ethtool interface for driver configuration and
   diagnostics, as well as displaying statistical information.  The ethtool
diff --git a/Documentation/networking/ixgbe.txt b/Documentation/networking/ixgbe.txt
index af77ed3..96ccceb 100644
--- a/Documentation/networking/ixgbe.txt
+++ b/Documentation/networking/ixgbe.txt
@@ -1,8 +1,9 @@
-Linux Base Driver for 10 Gigabit PCI Express Intel(R) Network Connection
-========================================================================
+Linux* Base Driver for the Intel(R) Ethernet 10 Gigabit PCI Express Family of
+Adapters
+=============================================================================
 
-Intel Gigabit Linux driver.
-Copyright(c) 1999 - 2010 Intel Corporation.
+Intel 10 Gigabit Linux driver.
+Copyright(c) 1999 - 2013 Intel Corporation.
 
 Contents
 ========
@@ -16,8 +17,8 @@ Contents
 Identifying Your Adapter
 ========================
 
-The driver in this release is compatible with 82598 and 82599-based Intel
-Network Connections.
+The driver in this release is compatible with 82598, 82599 and X540-based
+Intel Network Connections.
 
 For more information on how to identify your adapter, go to the Adapter &
 Driver ID Guide at:
@@ -72,7 +73,7 @@ cables that comply with SFF-8431 v4.1 and SFF-8472 v10.4 specifications.
 Laser turns off for SFP+ when ifconfig down
 -------------------------------------------
 "ifconfig down" turns off the laser for 82599-based SFP+ fiber adapters.
-"ifconfig up" turns on the later.
+"ifconfig up" turns on the laser.
 
 
 82598-BASED ADAPTERS
@@ -118,6 +119,93 @@ NOTE: For 82598 backplane cards entering 1 gig mode, flow control default
 behavior is changed to off.  Flow control in 1 gig mode on these devices can
 lead to Tx hangs.
 
+Intel(R) Ethernet Flow Director
+-------------------------------
+Supports advanced filters that direct receive packets by their flows to
+different queues. Enables tight control on routing a flow in the platform.
+Matches flows and CPU cores for flow affinity. Supports multiple parameters
+for flexible flow classification and load balancing.
+
+Flow director is enabled only if the kernel is multiple TX queue capable.
+
+An included script (set_irq_affinity.sh) automates setting the IRQ to CPU
+affinity.
+
+You can verify that the driver is using Flow Director by looking at the counter
+in ethtool: fdir_miss and fdir_match.
+
+Other ethtool Commands:
+To enable Flow Director
+	ethtool -K ethX ntuple on
+To add a filter
+	Use -U switch. e.g., ethtool -U ethX flow-type tcp4 src-ip 0x178000a
+        action 1
+To see the list of filters currently present:
+	ethtool -u ethX
+
+Perfect Filter: Perfect filter is an interface to load the filter table that
+funnels all flow into queue_0 unless an alternative queue is specified using
+"action". In that case, any flow that matches the filter criteria will be
+directed to the appropriate queue.
+
+If the queue is defined as -1, filter will drop matching packets.
+
+To account for filter matches and misses, there are two stats in ethtool:
+fdir_match and fdir_miss. In addition, rx_queue_N_packets shows the number of
+packets processed by the Nth queue.
+
+NOTE: Receive Packet Steering (RPS) and Receive Flow Steering (RFS) are not
+compatible with Flow Director. IF Flow Director is enabled, these will be
+disabled.
+
+The following three parameters impact Flow Director.
+
+FdirMode
+--------
+Valid Range: 0-2 (0=off, 1=ATR, 2=Perfect filter mode)
+Default Value: 1
+
+  Flow Director filtering modes.
+
+FdirPballoc
+-----------
+Valid Range: 0-2 (0=64k, 1=128k, 2=256k)
+Default Value: 0
+
+  Flow Director allocated packet buffer size.
+
+AtrSampleRate
+--------------
+Valid Range: 1-100
+Default Value: 20
+
+  Software ATR Tx packet sample rate. For example, when set to 20, every 20th
+  packet, looks to see if the packet will create a new flow.
+
+Node
+----
+Valid Range:   0-n
+Default Value: 1 (off)
+
+  0 - n: where n is the number of NUMA nodes (i.e. 0 - 3) currently online in
+  your system
+  1: turns this option off
+
+  The Node parameter will allow you to pick which NUMA node you want to have
+  the adapter allocate memory on.
+
+max_vfs
+-------
+Valid Range:   1-63
+Default Value: 0
+
+  If the value is greater than 0 it will also force the VMDq parameter to be 1
+  or more.
+
+  This parameter adds support for SR-IOV.  It causes the driver to spawn up to
+  max_vfs worth of virtual function.
+
+
 Additional Configurations
 =========================
 
@@ -221,9 +309,10 @@ http://www.redhat.com/promo/summit/2008/downloads/pdf/Thursday/Mark_Wagner.pdf
 Known Issues
 ============
 
-  Enabling SR-IOV in a 32-bit Microsoft* Windows* Server 2008 Guest OS using
-  Intel (R) 82576-based GbE or Intel (R) 82599-based 10GbE controller under KVM
-  -----------------------------------------------------------------------------
+  Enabling SR-IOV in a 32-bit or 64-bit Microsoft* Windows* Server 2008/R2
+  Guest OS using Intel (R) 82576-based GbE or Intel (R) 82599-based 10GbE
+  controller under KVM
+  ------------------------------------------------------------------------
   KVM Hypervisor/VMM supports direct assignment of a PCIe device to a VM.  This
   includes traditional PCIe devices, as well as SR-IOV-capable devices using
   Intel 82576-based and 82599-based controllers.
diff --git a/Documentation/networking/ixgbevf.txt b/Documentation/networking/ixgbevf.txt
index 5a91a41..53d8d2a 100644
--- a/Documentation/networking/ixgbevf.txt
+++ b/Documentation/networking/ixgbevf.txt
@@ -1,8 +1,8 @@
-Linux* Base Driver for Intel(R) Network Connection
-==================================================
+Linux* Base Driver for Intel(R) Ethernet Network Connection
+===========================================================
 
 Intel Gigabit Linux driver.
-Copyright(c) 1999 - 2010 Intel Corporation.
+Copyright(c) 1999 - 2013 Intel Corporation.
 
 Contents
 ========
-- 
1.8.3.1

^ permalink raw reply related

* Re: [net-next 1/2] Documentation/networking/: Update Intel wired LAN driver documentation
From: Jeff Kirsher @ 2013-08-24  0:09 UTC (permalink / raw)
  To: Ben Hutchings; +Cc: davem, netdev, gospo, sassmann
In-Reply-To: <1377262419.3364.11.camel@bwh-desktop.uk.level5networks.com>

[-- Attachment #1: Type: text/plain, Size: 2238 bytes --]

On Fri, 2013-08-23 at 13:53 +0100, Ben Hutchings wrote:
> On Fri, 2013-08-23 at 05:29 -0700, Jeff Kirsher wrote:
> > Updates the documentation to the Intel wired LAN drivers.
> 
> Except e100.txt which seems to be moving backward in time:
> 
> [...]
> > --- a/Documentation/networking/e100.txt
> > +++ b/Documentation/networking/e100.txt
> > @@ -1,7 +1,7 @@
> >  Linux* Base Driver for the Intel(R) PRO/100 Family of Adapters
> >  ==============================================================
> >  
> > -November 15, 2005
> > +March 15, 2011
> >  
> >  Contents
> >  ========
> > @@ -94,8 +94,8 @@ Additional Configurations
> >  
> >    Configuring a network driver to load properly when the system is started is
> >    distribution dependent. Typically, the configuration process involves adding
> > -  an alias line to /etc/modprobe.d/*.conf as well as editing other system
> > -  startup scripts and/or configuration files.  Many popular Linux
> > +  an alias line to /etc/modules.conf or /etc/modprobe.conf as well as editing
> 
> Reverting this fix:
> 
> commit 970e2486492aa1eb47a436a5a4c81e92558986a9
> Author: Lucas De Marchi <lucas.demarchi@profusion.mobi>
> Date:   Fri Mar 30 13:37:16 2012 -0700
> 
>     Documentation: remove references to /etc/modprobe.conf
> 
> [...]
> >    Enabling Wake on LAN* (WoL)
> >    ---------------------------
> > -  WoL is provided through the ethtool* utility.  For instructions on enabling
> > -  WoL with ethtool, refer to the ethtool man page.
> > +  WoL is provided through the ethtool* utility. The ethtool utility is included
> > +  with Red Hat* 8.0. For other Linux distributions, download and install
> [...]
> 
> And part of this one:
> 
> commit 68f20d948c86bd6bbc075052f6b6c45b8f56957e
> Author: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
> Date:   Fri Dec 17 12:14:34 2010 +0000
> 
>     Documentation/networking: Update Intel Wired LAN docs
> 
> Mentioning a 2002 distribution is completely pointless.
> 
> Ben.
> 

Thanks Ben, I will drop all the e100.txt changes at this point.  The
driver has little to no changes in the last couple of years, so the
documentation should not be changing.

I will re-spin with a v2.

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox