Netdev List
 help / color / mirror / Atom feed
* Re: [PATCH] USB2NET : SR9700 : One Chip USB 1.1 USB2NET SR9700 Device Driver Support
From: Francois Romieu @ 2013-08-29 23:06 UTC (permalink / raw)
  To: liujunliang_ljl
  Cc: davem, horms, joe, gregkh, netdev, linux-usb, linux-kernel,
	sunhecheng
In-Reply-To: <1377746832-6201-1-git-send-email-liujunliang_ljl@163.com>

Liu, please check those.

---
 drivers/net/usb/sr9700.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/net/usb/sr9700.c b/drivers/net/usb/sr9700.c
index 3f05b35..3ae3caf 100644
--- a/drivers/net/usb/sr9700.c
+++ b/drivers/net/usb/sr9700.c
@@ -99,8 +99,9 @@ static int sr_share_read_word(struct usbnet *dev, int phy, u8 reg,
 
 	mutex_lock(&dev->phy_mutex);
 
+	// FIXME: the mistery 0x40 appears in sr_share_write_word as well.
 	sr_write_reg(dev, EPAR, phy ? (reg | 0x40) : reg);
-	sr_write_reg(dev, EPCR, phy ? 0xc : 0x4);
+	sr_write_reg(dev, EPCR, phy ? (EPCR_EPOS | EPCR_ERPRR) : EPCR_ERPRR);
 
 	ret = wait_phy_eeprom_ready(dev, phy);
 	if (ret < 0)
@@ -128,7 +129,10 @@ static int sr_share_write_word(struct usbnet *dev, int phy, u8 reg,
 	if (ret < 0)
 		goto out_unlock;
 
+	// FIXME: see sr_share_read_word above.
 	sr_write_reg(dev, EPAR, phy ? (reg | 0x40) : reg);
+	// 0x1a -> EPCR_WEP | EPCR_EPOS | EPCR_ERPRW ?
+	// 0x12 -> EPCR_WEP | EPCR_ERPRW ?
 	sr_write_reg(dev, EPCR, phy ? 0x1a : 0x12);
 
 	ret = wait_phy_eeprom_ready(dev, phy);
-- 
1.8.3.1

^ permalink raw reply related

* Re: [PATCH] USB2NET : SR9700 : One Chip USB 1.1 USB2NET SR9700 Device Driver Support
From: Francois Romieu @ 2013-08-29 23:06 UTC (permalink / raw)
  To: liujunliang_ljl
  Cc: davem, horms, joe, gregkh, netdev, linux-usb, linux-kernel,
	sunhecheng
In-Reply-To: <1377746832-6201-1-git-send-email-liujunliang_ljl@163.com>

- use all columns
- the driver uses both 'netdev' and 'net'. Let's use 'netdev' ('net' is
  shorter but it tastes of network namespaces)
- don't dereference dev->net when there is a local netdev at hand
- use some existing #define (please check those)
- skb_set_tail_pointer to avoid compiler cast warnings

Pick whatever you want. skb_set_tail_pointer if nothing else.

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

diff --git a/drivers/net/usb/sr9700.c b/drivers/net/usb/sr9700.c
index 76e11f5..f7f46e6 100644
--- a/drivers/net/usb/sr9700.c
+++ b/drivers/net/usb/sr9700.c
@@ -28,8 +28,8 @@ 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);
+	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;
@@ -39,8 +39,8 @@ 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);
+	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;
@@ -158,11 +158,11 @@ static int sr9700_get_eeprom_len(struct net_device *dev)
 	return SR_EEPROM_LEN;
 }
 
-static int sr9700_get_eeprom(struct net_device *net,
+static int sr9700_get_eeprom(struct net_device *netdev,
 			     struct ethtool_eeprom *eeprom, u8 *data)
 {
-	struct usbnet *dev = netdev_priv(net);
-	__le16 *ebuf = (__le16 *)data;
+	struct usbnet *dev = netdev_priv(netdev);
+	__le16 *buf = (__le16 *)data;
 	int ret = 0;
 	int i;
 
@@ -170,9 +170,11 @@ static int sr9700_get_eeprom(struct net_device *net,
 	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]);
+	for (i = 0; i < eeprom->len / 2; i++) {
+		ret = sr_read_eeprom_word(dev, eeprom->offset / 2 + i, buf + i);
+		if (ret < 0)
+			break;
+	}
 
 	return ret;
 }
@@ -184,7 +186,7 @@ static int sr_mdio_read(struct net_device *netdev, int phy_id, int loc)
 	int rc = 0;
 
 	if (phy_id) {
-		netdev_dbg(dev->net, "Only internal phy supported\n");
+		netdev_dbg(netdev, "Only internal phy supported\n");
 		return 0;
 	}
 
@@ -202,7 +204,7 @@ static int sr_mdio_read(struct net_device *netdev, int phy_id, int loc)
 	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",
+	netdev_dbg(netdev, "sr_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n",
 		   phy_id, loc, res);
 
 	return res;
@@ -215,19 +217,19 @@ static void sr_mdio_write(struct net_device *netdev, int phy_id, int loc,
 	__le16 res = cpu_to_le16(val);
 
 	if (phy_id) {
-		netdev_dbg(dev->net, "Only internal phy supported\n");
+		netdev_dbg(netdev, "Only internal phy supported\n");
 		return;
 	}
 
-	netdev_dbg(dev->net, "sr_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\n",
+	netdev_dbg(netdev, "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)
+static u32 sr9700_get_link(struct net_device *netdev)
 {
-	struct usbnet *dev = netdev_priv(net);
+	struct usbnet *dev = netdev_priv(netdev);
 	u8 value = 0;
 	int rc = 0;
 
@@ -239,9 +241,9 @@ static u32 sr9700_get_link(struct net_device *net)
 	return rc;
 }
 
-static int sr9700_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
+static int sr9700_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
 {
-	struct usbnet *dev = netdev_priv(net);
+	struct usbnet *dev = netdev_priv(netdev);
 
 	return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
 }
@@ -258,9 +260,9 @@ static const struct ethtool_ops sr9700_ethtool_ops = {
 	.nway_reset	= usbnet_nway_reset,
 };
 
-static void sr9700_set_multicast(struct net_device *net)
+static void sr9700_set_multicast(struct net_device *netdev)
 {
-	struct usbnet *dev = netdev_priv(net);
+	struct usbnet *dev = netdev_priv(netdev);
 	/* We use the 20 byte dev->data for our 8 byte filter buffer
 	 * to avoid allocating memory that is tricky to free later
 	 */
@@ -271,14 +273,15 @@ static void sr9700_set_multicast(struct net_device *net)
 	memset(hashes, 0x00, SR_MCAST_SIZE);
 	/* broadcast address */
 	hashes[SR_MCAST_SIZE - 1] |= SR_MCAST_ADDR_FLAG;
-	if (net->flags & IFF_PROMISC) {
+	if (netdev->flags & IFF_PROMISC) {
 		rx_ctl |= RCR_PRMSC;
-	} else if (net->flags & IFF_ALLMULTI ||
-		   netdev_mc_count(net) > SR_MCAST_MAX) {
+	} else if (netdev->flags & IFF_ALLMULTI ||
+		   netdev_mc_count(netdev) > SR_MCAST_MAX) {
 		rx_ctl |= RCR_RUNT;
-	} else if (!netdev_mc_empty(net)) {
+	} else if (!netdev_mc_empty(netdev)) {
 		struct netdev_hw_addr *ha;
-		netdev_for_each_mc_addr(ha, net) {
+
+		netdev_for_each_mc_addr(ha, netdev) {
 			u32 crc = ether_crc(ETH_ALEN, ha->addr) >> 26;
 			hashes[crc >> 3] |= 1 << (crc & 0x7);
 		}
@@ -288,19 +291,19 @@ static void sr9700_set_multicast(struct net_device *net)
 	sr_write_reg_async(dev, RCR, rx_ctl);
 }
 
-static int sr9700_set_mac_address(struct net_device *net, void *p)
+static int sr9700_set_mac_address(struct net_device *netdev, void *p)
 {
-	struct usbnet *dev = netdev_priv(net);
+	struct usbnet *dev = netdev_priv(netdev);
 	struct sockaddr *addr = p;
 
 	if (!is_valid_ether_addr(addr->sa_data)) {
-		netdev_err(net, "not setting invalid mac address %pM\n",
+		netdev_err(netdev, "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);
+	memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
+	sr_write_async(dev, PAR, 6, netdev->dev_addr);
 
 	return 0;
 }
@@ -319,26 +322,31 @@ static const struct net_device_ops sr9700_netdev_ops = {
 
 static int sr9700_bind(struct usbnet *dev, struct usb_interface *intf)
 {
+	struct net_device *netdev;
+	struct mii_if_info *mii;
 	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;
+	netdev = dev->net;
+
+	netdev->netdev_ops = &sr9700_netdev_ops;
+	netdev->ethtool_ops = &sr9700_ethtool_ops;
+	netdev->hard_header_len += SR_TX_OVERHEAD;
+	dev->hard_mtu = netdev->mtu + netdev->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);
+
+	mii = &dev->mii;
+	mii->dev = netdev;
+	mii->mdio_read = sr_mdio_read;
+	mii->mdio_write = sr_mdio_write;
+	mii->phy_id_mask = 0x1f;
+	mii->reg_num_mask = 0x1f;
+
+	sr_write_reg(dev, NCR, NCR_RST);
 	udelay(20);
 
 	/* read MAC
@@ -346,14 +354,14 @@ static int sr9700_bind(struct usbnet *dev, struct usb_interface *intf)
 	 * 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");
+	if (sr_read(dev, PAR, ETH_ALEN, netdev->dev_addr) < 0) {
+		netdev_err(netdev, "Error reading MAC address\n");
 		ret = -ENODEV;
 		goto out;
 	}
 
 	/* power up and reset phy */
-	sr_write_reg(dev, PRR, 1);
+	sr_write_reg(dev, PRR, PRR_PHY_RST);
 	/* at least 10ms, here 20ms for safe */
 	mdelay(20);
 	sr_write_reg(dev, PRR, 0);
@@ -361,13 +369,12 @@ static int sr9700_bind(struct usbnet *dev, struct usb_interface *intf)
 	udelay(2 * 1000);
 
 	/* receive broadcast packets */
-	sr9700_set_multicast(dev->net);
+	sr9700_set_multicast(netdev);
 
-	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);
+	sr_mdio_write(netdev, mii->phy_id, MII_BMCR, BMCR_RESET);
+	sr_mdio_write(netdev, mii->phy_id, MII_ADVERTISE, ADVERTISE_ALL |
+		      ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
+	mii_nway_restart(mii);
 
 out:
 	return ret;
@@ -415,7 +422,7 @@ static int sr9700_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
 		if (skb->len == (len + SR_RX_OVERHEAD))	{
 			skb_pull(skb, 3);
 			skb->len = len;
-			skb->tail = skb->data + len;
+			skb_set_tail_pointer(skb, len);
 			skb->truesize = len + sizeof(struct sk_buff);
 			return 2;
 		}
@@ -427,7 +434,7 @@ static int sr9700_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
 
 		sr_skb->len = len;
 		sr_skb->data = skb->data + 3;
-		sr_skb->tail = skb->data + len;
+		skb_set_tail_pointer(sr_skb, len - 3);
 		sr_skb->truesize = len + sizeof(struct sk_buff);
 		usbnet_skb_return(dev, sr_skb);
 
-- 
1.8.3.1

^ permalink raw reply related

* [PATCH v2 net-next] pkt_sched: fq: Fair Queue packet scheduler
From: Eric Dumazet @ 2013-08-29 22:49 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, Yuchung Cheng, Neal Cardwell

From: Eric Dumazet <edumazet@google.com>

- Uses perfect flow match (not stochastic hash like SFQ/FQ_codel)
- Uses the new_flow/old_flow separation from FQ_codel
- New flows get an initial credit allowing IW10 without added delay.
- 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 : ~8K per Qdisc, and 104 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, and applications delivering chunks of data
as video streams.

Nicely spaced packets :
Here interface is 10Gbit, but flow bottleneck is ~20Mbit

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

15:01:23.545279 IP A > B: . 78193:81089(2896) ack 65248 win 3125 <nop,nop,timestamp 1115 11597805>
15:01:23.545394 IP B > A: . ack 81089 win 3668 <nop,nop,timestamp 11597985 1115>
15:01:23.546488 IP A > B: . 81089:83985(2896) ack 65248 win 3125 <nop,nop,timestamp 1115 11597805>
15:01:23.546565 IP B > A: . ack 83985 win 3668 <nop,nop,timestamp 11597986 1115>
15:01:23.547713 IP A > B: . 83985:86881(2896) ack 65248 win 3125 <nop,nop,timestamp 1115 11597805>
15:01:23.547778 IP B > A: . ack 86881 win 3668 <nop,nop,timestamp 11597987 1115>
15:01:23.548911 IP A > B: . 86881:89777(2896) ack 65248 win 3125 <nop,nop,timestamp 1115 11597805>
15:01:23.548949 IP B > A: . ack 89777 win 3668 <nop,nop,timestamp 11597988 1115>
15:01:23.550116 IP A > B: . 89777:92673(2896) ack 65248 win 3125 <nop,nop,timestamp 1115 11597805>
15:01:23.550182 IP B > A: . ack 92673 win 3668 <nop,nop,timestamp 11597989 1115>
15:01:23.551333 IP A > B: . 92673:95569(2896) ack 65248 win 3125 <nop,nop,timestamp 1115 11597805>
15:01:23.551406 IP B > A: . ack 95569 win 3668 <nop,nop,timestamp 11597991 1115>
15:01:23.552539 IP A > B: . 95569:98465(2896) ack 65248 win 3125 <nop,nop,timestamp 1115 11597805>
15:01:23.552576 IP B > A: . ack 98465 win 3668 <nop,nop,timestamp 11597992 1115>
15:01:23.553756 IP A > B: . 98465:99913(1448) ack 65248 win 3125 <nop,nop,timestamp 1115 11597805>
15:01:23.554138 IP A > B: P 99913:100001(88) ack 65248 win 3125 <nop,nop,timestamp 1115 11597805>
15:01:23.554204 IP B > A: . ack 100001 win 3668 <nop,nop,timestamp 11597993 1115>
15:01:23.554234 IP B > A: . 65248:68144(2896) ack 100001 win 3668 <nop,nop,timestamp 11597993 1115>
15:01:23.555620 IP B > A: . 68144:71040(2896) ack 100001 win 3668 <nop,nop,timestamp 11597993 1115>
15:01:23.557005 IP B > A: . 71040:73936(2896) ack 100001 win 3668 <nop,nop,timestamp 11597993 1115>
15:01:23.558390 IP B > A: . 73936:76832(2896) ack 100001 win 3668 <nop,nop,timestamp 11597993 1115>
15:01:23.559773 IP B > A: . 76832:79728(2896) ack 100001 win 3668 <nop,nop,timestamp 11597993 1115>
15:01:23.561158 IP B > A: . 79728:82624(2896) ack 100001 win 3668 <nop,nop,timestamp 11597994 1115>
15:01:23.562543 IP B > A: . 82624:85520(2896) ack 100001 win 3668 <nop,nop,timestamp 11597994 1115>
15:01:23.563928 IP B > A: . 85520:88416(2896) ack 100001 win 3668 <nop,nop,timestamp 11597994 1115>
15:01:23.565313 IP B > A: . 88416:91312(2896) ack 100001 win 3668 <nop,nop,timestamp 11597994 1115>
15:01:23.566698 IP B > A: . 91312:94208(2896) ack 100001 win 3668 <nop,nop,timestamp 11597994 1115>
15:01:23.568083 IP B > A: . 94208:97104(2896) ack 100001 win 3668 <nop,nop,timestamp 11597994 1115>
15:01:23.569467 IP B > A: . 97104:100000(2896) ack 100001 win 3668 <nop,nop,timestamp 11597994 1115>
15:01:23.570852 IP B > A: . 100000:102896(2896) ack 100001 win 3668 <nop,nop,timestamp 11597994 1115>
15:01:23.572237 IP B > A: . 102896:105792(2896) ack 100001 win 3668 <nop,nop,timestamp 11597994 1115>
15:01:23.573639 IP B > A: . 105792:108688(2896) ack 100001 win 3668 <nop,nop,timestamp 11597994 1115>
15:01:23.575024 IP B > A: . 108688:111584(2896) ack 100001 win 3668 <nop,nop,timestamp 11597994 1115>
15:01:23.576408 IP B > A: . 111584:114480(2896) ack 100001 win 3668 <nop,nop,timestamp 11597994 1115>
15:01:23.577793 IP B > A: . 114480:117376(2896) ack 100001 win 3668 <nop,nop,timestamp 11597994 1115>

TCP timestamps show that most packets from B were queued in the same ms
timeframe (TSval 1159799{3,4}), but FQ managed to send them right
in time to avoid a big burst.

In slow start or steady state, very few packets are throttled [1]

FQ gets a bunch of tunables as :

  limit : max number of packets on whole Qdisc (default 10000)

  flow_limit : max number of packets per flow (default 100)

  quantum : the credit per RR round (default is 2 MTU)

  initial_quantum : initial credit for new flows (default is 10 MTU)

  maxrate : max per flow rate (default : unlimited)

  buckets : number of RB trees (default : 1024) in hash table.
               (consumes 8 bytes per bucket)

  [no]pacing : disable/enable pacing (default is enable)

All of them can be changed on a live qdisc.

$ tc qd add dev eth0 root fq help
Usage: ... fq [ limit PACKETS ] [ flow_limit PACKETS ]
              [ quantum BYTES ] [ initial_quantum BYTES ]
              [ maxrate RATE  ] [ buckets NUMBER ]
              [ [no]pacing ]

$ tc -s -d qd
qdisc fq 8002: dev eth0 root refcnt 32 limit 10000p flow_limit 100p buckets 256 quantum 3028 initial_quantum 15140
 Sent 216532416 bytes 148395 pkt (dropped 0, overlimits 0 requeues 14)
 backlog 0b 0p requeues 14
  511 flows, 511 inactive, 0 throttled
  110 gc, 0 highprio, 0 retrans, 1143 throttled, 0 flows_plimit


[1] Except if initial srtt is overestimated, as if using
cached srtt in tcp metrics. We'll provide a fix for this issue.

Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Yuchung Cheng <ycheng@google.com>
Cc: Neal Cardwell <ncardwell@google.com>
---
v2: added initial_quantum support

 include/uapi/linux/pkt_sched.h |   41 +
 net/sched/Kconfig              |   14 
 net/sched/Makefile             |    1 
 net/sched/sch_fq.c             |  792 +++++++++++++++++++++++++++++++
 4 files changed, 848 insertions(+)

diff --git a/include/uapi/linux/pkt_sched.h b/include/uapi/linux/pkt_sched.h
index 09d62b92..9b82913 100644
--- a/include/uapi/linux/pkt_sched.h
+++ b/include/uapi/linux/pkt_sched.h
@@ -744,4 +744,45 @@ 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_INITIAL_QUANTUM,		/* RR quantum for new flow */
+
+	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;
+	__s64	time_next_delayed_flow;
+	__u32	flows;
+	__u32	inactive_flows;
+	__u32	throttled_flows;
+	__u32	pad;
+};
 #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..d46d0ec
--- /dev/null
+++ b/net/sched/sch_fq.c
@@ -0,0 +1,792 @@
+/*
+ * 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 mostly 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 1024 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		credit;
+	u32		socket_hash;	/* sk_hash */
+	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		initial_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) {
+			/* socket might have been reallocated, so check
+			 * if its sk_hash is the same.
+			 * It not, we need to refill credit with
+			 * initial quantum
+			 */
+			if (unlikely(skb->sk &&
+				     f->socket_hash != sk->sk_hash)) {
+				f->credit = q->initial_quantum;
+				f->socket_hash = sk->sk_hash;
+			}
+			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;
+	if (skb->sk)
+		f->socket_hash = sk->sk_hash;
+	f->credit = q->initial_quantum;
+
+	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 (unlikely(sch->q.qlen >= sch->limit))
+		return qdisc_drop(skb, sch);
+
+	f = fq_classify(skb, q);
+	if (unlikely(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);
+		if (q->quantum > f->credit)
+			f->credit = q->quantum;
+		q->inactive_flows--;
+		qdisc_unthrottled(sch);
+	}
+	if (unlikely(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->credit <= 0) {
+		f->credit += q->quantum;
+		head->first = f->next;
+		fq_flow_add_tail(&q->old_flows, f);
+		goto begin;
+	}
+
+	if (unlikely(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->time_next_packet = now;
+	f->credit -= qdisc_pkt_len(skb);
+
+	if (f->credit <= 0 &&
+	    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_INITIAL_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_INITIAL_QUANTUM])
+		q->quantum = nla_get_u32(tb[TCA_FQ_INITIAL_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->initial_quantum	= 10 * 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(1024);
+	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_INITIAL_QUANTUM, q->initial_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);
+	u64 now = ktime_to_ns(ktime_get());
+	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,
+		.flows			= q->flows,
+		.inactive_flows		= q->inactive_flows,
+		.throttled_flows	= q->throttled_flows,
+		.time_next_delayed_flow	= q->time_next_delayed_flow - now,
+	};
+
+	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] net: ipv6: mldv1/v2: fix switchback timeout to rfc3810, 9.12.
From: David Miller @ 2013-08-29 22:14 UTC (permalink / raw)
  To: dborkman; +Cc: netdev, dlstevens, hannes
In-Reply-To: <521FBC29.2090700@redhat.com>

From: Daniel Borkmann <dborkman@redhat.com>
Date: Thu, 29 Aug 2013 23:24:57 +0200

> Dave, please hold on with this one. This is already better, but
> it still needs to be improved slightly. Will send an update tomorrow
> or at latest at the beginning of next week.

Ok.

^ permalink raw reply

* Re: [-next] openvswitch BUILD_BUG_ON failed
From: David Miller @ 2013-08-29 22:10 UTC (permalink / raw)
  To: jesse; +Cc: geert, azhou, dev, netdev, linux-kernel, linux-next
In-Reply-To: <CAEP_g=-XvRiHPzSAp2rgC9Hxdd+pGEHvSTEJ1A1SkWnk1-6xZA@mail.gmail.com>

From: Jesse Gross <jesse@nicira.com>
Date: Thu, 29 Aug 2013 14:42:22 -0700

> On Thu, Aug 29, 2013 at 2:21 PM, Geert Uytterhoeven
> <geert@linux-m68k.org> wrote:
>> However, I have some doubts about other alignment "enforcements":
>>
>> "__aligned(__alignof__(long))" makes the whole struct aligned to the
>> alignment rule for "long":
>>    1. This is only 2 bytes on m68k, i.e. != sizeof(long).
>>    2. This is 4 bytes on many 32-bit platforms, which may be less than the
>>       default alignment for "__be64" (cfr. some members of struct
>>       ovs_key_ipv4_tunnel), so this may make those 64-bit members unaligned.
> 
> Do any of those 32-bit architectures actually care about alignment of
> 64 bit values? On 32-bit x86, a long is 32 bits but the alignment
> requirement of __be64 is also 32 bit.

All except x86-32 do, it is in fact the odd man out with respect to this
issue.

^ permalink raw reply

* [PATCH net] net: bridge: convert MLDv2 Query MRC into msecs_to_jiffies for max_delay
From: Daniel Borkmann @ 2013-08-29 21:55 UTC (permalink / raw)
  To: davem; +Cc: netdev, Linus Lüssing, Hannes Frederic Sowa

While looking into MLDv1/v2 code, I noticed that bridging code does
not convert it's max delay into jiffies for MLDv2 messages as we do
in core IPv6' multicast code.

RFC3810, 5.1.3. Maximum Response Code says:

  The Maximum Response Code field specifies the maximum time allowed
  before sending a responding Report. The actual time allowed, called
  the Maximum Response Delay, is represented in units of milliseconds,
  and is derived from the Maximum Response Code as follows: [...]

As we update timers that work with jiffies, we need to convert it.

Signed-off-by: Daniel Borkmann <dborkman@redhat.com>
Cc: Linus Lüssing <linus.luessing@web.de>
Cc: Hannes Frederic Sowa <hannes@stressinduktion.org>
---
 net/bridge/br_multicast.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 08e576a..08d2921 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -1203,7 +1203,8 @@ static int br_ip6_multicast_query(struct net_bridge *br,
 		mld2q = (struct mld2_query *)icmp6_hdr(skb);
 		if (!mld2q->mld2q_nsrcs)
 			group = &mld2q->mld2q_mca;
-		max_delay = mld2q->mld2q_mrc ? MLDV2_MRC(ntohs(mld2q->mld2q_mrc)) : 1;
+
+		max_delay = max(msecs_to_jiffies(MLDV2_MRC(ntohs(mld2q->mld2q_mrc))), 1UL);
 	}
 
 	br_multicast_query_received(br, port, !ipv6_addr_any(&ip6h->saddr),
-- 
1.7.11.7

^ permalink raw reply related

* Re: [-next] openvswitch BUILD_BUG_ON failed
From: Jesse Gross @ 2013-08-29 21:42 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: Andy Zhou, dev@openvswitch.org, netdev@vger.kernel.org,
	linux-kernel@vger.kernel.org, Linux-Next
In-Reply-To: <CAMuHMdVG9FmZNayrf7HMz4kC4X5QELeXUFjjzpAM80ND_QOm8A@mail.gmail.com>

On Thu, Aug 29, 2013 at 2:21 PM, Geert Uytterhoeven
<geert@linux-m68k.org> wrote:
> However, I have some doubts about other alignment "enforcements":
>
> "__aligned(__alignof__(long))" makes the whole struct aligned to the
> alignment rule for "long":
>    1. This is only 2 bytes on m68k, i.e. != sizeof(long).
>    2. This is 4 bytes on many 32-bit platforms, which may be less than the
>       default alignment for "__be64" (cfr. some members of struct
>       ovs_key_ipv4_tunnel), so this may make those 64-bit members unaligned.

Do any of those 32-bit architectures actually care about alignment of
64 bit values? On 32-bit x86, a long is 32 bits but the alignment
requirement of __be64 is also 32 bit.

^ permalink raw reply

* Re: [-next] openvswitch BUILD_BUG_ON failed
From: Andy Zhou @ 2013-08-29 21:40 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: dev-yBygre7rU0TnMu66kgdUjQ@public.gmane.org,
	netdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Linux-Next,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <CAMuHMdVG9FmZNayrf7HMz4kC4X5QELeXUFjjzpAM80ND_QOm8A-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>


[-- Attachment #1.1: Type: text/plain, Size: 3350 bytes --]

Yes, fengguan.Wu has reported the issue. Just sent out a patch for review.
You are welcome to review it.

http://openvswitch.org/pipermail/dev/2013-August/031247.html


On Thu, Aug 29, 2013 at 2:21 PM, Geert Uytterhoeven <geert-Td1EMuHUCqxL1ZNQvxDV9g@public.gmane.org>wrote:

> On m68k, where the alignment of 32-bit words is 2 bytes:
>
> net/openvswitch/flow.c:1984:2: error: call to
> '__compiletime_assert_1984' declared with attribute error:
> BUILD_BUG_ON failed: sizeof(struct sw_flow_key) % sizeof(long)
>
> (http://kisskb.ellerman.id.au/kisskb/buildresult/9422860/)
>
> This was introduced by commit 5828cd9a68873df1340b420371c02c47647878fb
> Author: Andy Zhou <azhou-l0M0P4e3n4LQT0dZR+AlfA@public.gmane.org>
> Date:   Tue Aug 27 13:02:21 2013 -0700
>
>     openvswitch: optimize flow compare and mask functions
>
>     Make sure the sw_flow_key structure and valid mask boundaries are
> always
>     machine word aligned. Optimize the flow compare and mask operations
>     using machine word size operations. This patch improves throughput on
>     average by 15% when CPU is the bottleneck of forwarding packets.
>
>     This patch is inspired by ideas and code from a patch submitted by
> Peter
>     Klausler titled "replace memcmp() with specialized comparator".
>     However, The original patch only optimizes for architectures
>     support unaligned machine word access. This patch optimizes for all
>     architectures.
>
> A quick fix to satisfy the build check is to make the padding explicit
> (gmail-whitespace-damaged diff):
>
> diff --git a/net/openvswitch/flow.h b/net/openvswitch/flow.h
> index b65f885..15f08d9 100644
> --- a/net/openvswitch/flow.h
> +++ b/net/openvswitch/flow.h
> @@ -78,6 +78,7 @@ struct sw_flow_key {
>                 u32     priority;       /* Packet QoS priority. */
>                 u32     skb_mark;       /* SKB mark. */
>                 u16     in_port;        /* Input switch port (or
> DP_MAX_PORTS).
> +               u16     pad;
>         } phy;
>         struct {
>                 u8     src[ETH_ALEN];   /* Ethernet source address. */
>
> However, I have some doubts about other alignment "enforcements":
>
> "__aligned(__alignof__(long))" makes the whole struct aligned to the
> alignment rule for "long":
>    1. This is only 2 bytes on m68k, i.e. != sizeof(long).
>    2. This is 4 bytes on many 32-bit platforms, which may be less than the
>       default alignment for "__be64" (cfr. some members of struct
>       ovs_key_ipv4_tunnel), so this may make those 64-bit members
> unaligned.
> I guess you want (at least) 4 byte alignment on 32-bit, and prefer 8 byte
> alignment on 64-bit?
> Not specifying any alignment constraint will give you most of that (except
> on 64-bit platforms where 64-bit words must be only 4-byte aligned).
>
> There's another build check "BUILD_BUG_ON(sizeof(long) % sizeof(u32))".
> Isn't this always true on Linux, as "long" is never smaller than 4 bytes?
>

Gr{oetje,eeting}s,
>
>                         Geert
>
> --
> Geert Uytterhoeven -- There's lots of Linux beyond ia32 --
> geert-Td1EMuHUCqxL1ZNQvxDV9g@public.gmane.org
>
> In personal conversations with technical people, I call myself a hacker.
> But
> when I'm talking to journalists I just say "programmer" or something like
> that.
>                                 -- Linus Torvalds
>

[-- Attachment #1.2: Type: text/html, Size: 4410 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply

* [PATCH net-next 2/2] bonding: use rlb_client_info->vlan_id instead of ->tag
From: Veaceslav Falico @ 2013-08-29 21:38 UTC (permalink / raw)
  To: netdev; +Cc: Veaceslav Falico, Jay Vosburgh, Andy Gospodarek
In-Reply-To: <1377812337-19551-1-git-send-email-vfalico@redhat.com>

Store VID in ->vlan_id (if any), and remove the useless ->tag.

CC: Jay Vosburgh <fubar@us.ibm.com>
CC: Andy Gospodarek <andy@greyhouse.net>
Signed-off-by: Veaceslav Falico <vfalico@redhat.com>
---
 drivers/net/bonding/bond_alb.c | 8 ++++----
 drivers/net/bonding/bond_alb.h | 1 -
 2 files changed, 4 insertions(+), 5 deletions(-)

diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index 27b03fa..91f179d 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -512,7 +512,7 @@ static void rlb_update_client(struct rlb_client_info *client_info)
 
 		skb->dev = client_info->slave->dev;
 
-		if (client_info->tag) {
+		if (client_info->vlan_id) {
 			skb = vlan_put_tag(skb, htons(ETH_P_8021Q), client_info->vlan_id);
 			if (!skb) {
 				pr_err("%s: Error: failed to insert VLAN tag\n",
@@ -695,7 +695,7 @@ static struct slave *rlb_choose_channel(struct sk_buff *skb, struct bonding *bon
 		}
 
 		if (!vlan_get_tag(skb, &client_info->vlan_id))
-			client_info->tag = 1;
+			client_info->vlan_id = 0;
 
 		if (!client_info->assigned) {
 			u32 prev_tbl_head = bond_info->rx_hashtbl_used_head;
@@ -801,7 +801,7 @@ static void rlb_init_table_entry_dst(struct rlb_client_info *entry)
 	entry->used_prev = RLB_NULL_INDEX;
 	entry->assigned = 0;
 	entry->slave = NULL;
-	entry->tag = 0;
+	entry->vlan_id = 0;
 }
 static void rlb_init_table_entry_src(struct rlb_client_info *entry)
 {
@@ -958,7 +958,7 @@ static void rlb_clear_vlan(struct bonding *bond, unsigned short vlan_id)
 		struct rlb_client_info *curr = &(bond_info->rx_hashtbl[curr_index]);
 		u32 next_index = bond_info->rx_hashtbl[curr_index].used_next;
 
-		if (curr->tag && (curr->vlan_id == vlan_id))
+		if (curr->vlan_id == vlan_id)
 			rlb_delete_table_entry(bond, curr_index);
 
 		curr_index = next_index;
diff --git a/drivers/net/bonding/bond_alb.h b/drivers/net/bonding/bond_alb.h
index e02c9c5..28d8e4c 100644
--- a/drivers/net/bonding/bond_alb.h
+++ b/drivers/net/bonding/bond_alb.h
@@ -125,7 +125,6 @@ struct rlb_client_info {
 	u8  assigned;		/* checking whether this entry is assigned */
 	u8  ntt;		/* flag - need to transmit client info */
 	struct slave *slave;	/* the slave assigned to this client */
-	u8 tag;			/* flag - need to tag skb */
 	unsigned short vlan_id;	/* VLAN tag associated with IP address */
 };
 
-- 
1.8.4

^ permalink raw reply related

* [PATCH net-next 1/2] bonding: remove bond_vlan_used()
From: Veaceslav Falico @ 2013-08-29 21:38 UTC (permalink / raw)
  To: netdev; +Cc: Veaceslav Falico, Jay Vosburgh, Andy Gospodarek
In-Reply-To: <1377812337-19551-1-git-send-email-vfalico@redhat.com>

We're using it currently to verify if we have vlans before getting the tag
from the skb we're about to send. It's useless because the vlan_get_tag()
verifies if the skb has the tag (and returns an error if not), and we can
receive tagged skbs only if we *already* have vlans.

Plus, the current RCUed implementation is kind of useless anyway - the we
can remove the last vlan in the moment we return from the function.

So remove the only usage of it and the whole function.

CC: Jay Vosburgh <fubar@us.ibm.com>
CC: Andy Gospodarek <andy@greyhouse.net>
Signed-off-by: Veaceslav Falico <vfalico@redhat.com>
---
 drivers/net/bonding/bond_alb.c |  6 ++----
 drivers/net/bonding/bonding.h  | 18 ------------------
 2 files changed, 2 insertions(+), 22 deletions(-)

diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index 0182352..27b03fa 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -694,10 +694,8 @@ static struct slave *rlb_choose_channel(struct sk_buff *skb, struct bonding *bon
 			client_info->ntt = 0;
 		}
 
-		if (bond_vlan_used(bond)) {
-			if (!vlan_get_tag(skb, &client_info->vlan_id))
-				client_info->tag = 1;
-		}
+		if (!vlan_get_tag(skb, &client_info->vlan_id))
+			client_info->tag = 1;
 
 		if (!client_info->assigned) {
 			u32 prev_tbl_head = bond_info->rx_hashtbl_used_head;
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index 4abc925..f7ab161 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -261,24 +261,6 @@ struct bonding {
 #endif /* CONFIG_DEBUG_FS */
 };
 
-/* if we hold rtnl_lock() - call vlan_uses_dev() */
-static inline bool bond_vlan_used(struct bonding *bond)
-{
-	struct net_device *upper;
-	struct list_head *iter;
-
-	rcu_read_lock();
-	netdev_for_each_upper_dev_rcu(bond->dev, upper, iter) {
-		if (upper->priv_flags & IFF_802_1Q_VLAN) {
-			rcu_read_unlock();
-			return true;
-		}
-	}
-	rcu_read_unlock();
-
-	return false;
-}
-
 #define bond_slave_get_rcu(dev) \
 	((struct slave *) rcu_dereference(dev->rx_handler_data))
 
-- 
1.8.4

^ permalink raw reply related

* [PATCH net-next 0/2] bonding: clean rlb vlan use
From: Veaceslav Falico @ 2013-08-29 21:38 UTC (permalink / raw)
  To: netdev; +Cc: Jay Vosburgh, Andy Gospodarek, Veaceslav Falico

Finish the vlan cleanup, only rlb left.

Remove the bond_vlan_used() function, it's useless anyway, and
rlb_client_info->tag, cause we can use only ->vlan_id.

CC: Jay Vosburgh <fubar@us.ibm.com>
CC: Andy Gospodarek <andy@greyhouse.net>
Signed-off-by: Veaceslav Falico <vfalico@redhat.com>

---
 drivers/net/bonding/bond_alb.c | 12 +++++-------
 drivers/net/bonding/bond_alb.h |  1 -
 drivers/net/bonding/bonding.h  | 18 ------------------
 3 files changed, 5 insertions(+), 26 deletions(-)

^ permalink raw reply

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

On Thu, 2013-08-29 at 16:35 -0400, David Miller wrote:

> 
> No objections from me.

We'll cook a different patch.

Idea is to feed tcp_set_rto() with the srtt found in the tcp metric
cache, and let tp->srtt value found in SYN/SYNACK (if available) as is.

(Be conservative for initial rto value, yet allow tp->srtt be the
current rtt on the network)

Thanks

^ permalink raw reply

* Re: [PATCH net-next] net: ipv6: mldv1/v2: fix switchback timeout to rfc3810, 9.12.
From: Daniel Borkmann @ 2013-08-29 21:24 UTC (permalink / raw)
  To: davem; +Cc: netdev, David Stevens, Hannes Frederic Sowa
In-Reply-To: <1377792578-32642-1-git-send-email-dborkman@redhat.com>

Dave, please hold on with this one. This is already better, but
it still needs to be improved slightly. Will send an update tomorrow
or at latest at the beginning of next week.

^ permalink raw reply

* [-next] openvswitch BUILD_BUG_ON failed
From: Geert Uytterhoeven @ 2013-08-29 21:21 UTC (permalink / raw)
  To: Andy Zhou, Jesse Gross
  Cc: dev-yBygre7rU0TnMu66kgdUjQ,
	netdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Linux-Next,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org

On m68k, where the alignment of 32-bit words is 2 bytes:

net/openvswitch/flow.c:1984:2: error: call to
'__compiletime_assert_1984' declared with attribute error:
BUILD_BUG_ON failed: sizeof(struct sw_flow_key) % sizeof(long)

(http://kisskb.ellerman.id.au/kisskb/buildresult/9422860/)

This was introduced by commit 5828cd9a68873df1340b420371c02c47647878fb
Author: Andy Zhou <azhou-l0M0P4e3n4LQT0dZR+AlfA@public.gmane.org>
Date:   Tue Aug 27 13:02:21 2013 -0700

    openvswitch: optimize flow compare and mask functions

    Make sure the sw_flow_key structure and valid mask boundaries are always
    machine word aligned. Optimize the flow compare and mask operations
    using machine word size operations. This patch improves throughput on
    average by 15% when CPU is the bottleneck of forwarding packets.

    This patch is inspired by ideas and code from a patch submitted by Peter
    Klausler titled "replace memcmp() with specialized comparator".
    However, The original patch only optimizes for architectures
    support unaligned machine word access. This patch optimizes for all
    architectures.

A quick fix to satisfy the build check is to make the padding explicit
(gmail-whitespace-damaged diff):

diff --git a/net/openvswitch/flow.h b/net/openvswitch/flow.h
index b65f885..15f08d9 100644
--- a/net/openvswitch/flow.h
+++ b/net/openvswitch/flow.h
@@ -78,6 +78,7 @@ struct sw_flow_key {
                u32     priority;       /* Packet QoS priority. */
                u32     skb_mark;       /* SKB mark. */
                u16     in_port;        /* Input switch port (or DP_MAX_PORTS).
+               u16     pad;
        } phy;
        struct {
                u8     src[ETH_ALEN];   /* Ethernet source address. */

However, I have some doubts about other alignment "enforcements":

"__aligned(__alignof__(long))" makes the whole struct aligned to the
alignment rule for "long":
   1. This is only 2 bytes on m68k, i.e. != sizeof(long).
   2. This is 4 bytes on many 32-bit platforms, which may be less than the
      default alignment for "__be64" (cfr. some members of struct
      ovs_key_ipv4_tunnel), so this may make those 64-bit members unaligned.
I guess you want (at least) 4 byte alignment on 32-bit, and prefer 8 byte
alignment on 64-bit?
Not specifying any alignment constraint will give you most of that (except
on 64-bit platforms where 64-bit words must be only 4-byte aligned).

There's another build check "BUILD_BUG_ON(sizeof(long) % sizeof(u32))".
Isn't this always true on Linux, as "long" is never smaller than 4 bytes?

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert-Td1EMuHUCqxL1ZNQvxDV9g@public.gmane.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply related

* Re: [PATCH net-next v10 10/11] vxlan: respect scope_id for ll addr
From: David Stevens @ 2013-08-29 21:20 UTC (permalink / raw)
  To: Cong Wang; +Cc: Cong Wang, David S. Miller, netdev, netdev-owner
In-Reply-To: <1377667379-2315-11-git-send-email-amwang@redhat.com>

netdev-owner@vger.kernel.org wrote on 08/28/2013 01:22:58 AM:

> From: Cong Wang <amwang@redhat.com>
 
> As pointed out by David, we should take care of scope id for ll
> addr, and use it for route lookup.

        It is an error to have a zero scope_id for an LL addr, but
this code is not correct, because it only honors scope_id for
LL addrs. Multicast addresses also require scope_id be set.
        This shouldn't be in the transmit path. The netlink code
that sets it should require it be nonzero for LL addrs and multicast
addrs when it is set, and the transmit path should *always* use scope_id,
whether for an lladdr or not, whether scope_id is zero or not.

        I'm away this week and won't be able to review these in
detail until next week, but wanted to get that comment in.

                                                +-DLS

^ permalink raw reply

* pull-request: can-next 2013-08-29
From: Marc Kleine-Budde @ 2013-08-29 21:13 UTC (permalink / raw)
  To: Linux Netdev List
  Cc: linux-can@vger.kernel.org, David Miller, kernel@pengutronix.de

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

Hello David,

this is a pull request for net-next. There are two patches from Gerhard
Sittig, which improves the clock handling on mpc5121. Oliver Hartkopp
provides a patch that adds a per rule limitation of frame hops.

regards,
Marc

---

The following changes since commit 7ec06da81d2b98859b558d8d551a0c4e3d9516a3:

  net: packet: document available fanout policies (2013-08-29 16:43:29 -0400)

are available in the git repository at:

  git://gitorious.org/linux-can/linux-can-next.git for-davem

for you to fetch changes up to 391ac1282dd7ff1cb8245cccc5262e8e4173edc4:

  can: gw: add a per rule limitation of frame hops (2013-08-29 22:58:24 +0200)

----------------------------------------------------------------
Gerhard Sittig (2):
      can: mscan: add a comment on reg to idx mapping
      can: mscan: improve clock API use

Oliver Hartkopp (1):
      can: gw: add a per rule limitation of frame hops

 drivers/net/can/mscan/mpc5xxx_can.c | 23 ++++++++++++++++-------
 drivers/net/can/mscan/mscan.c       | 25 ++++++++++++++++++++++++-
 drivers/net/can/mscan/mscan.h       |  3 +++
 include/uapi/linux/can/gw.h         |  9 ++++++++-
 net/can/gw.c                        | 35 +++++++++++++++++++++++++++++++----
 5 files changed, 82 insertions(+), 13 deletions(-)

-- 
Pengutronix e.K.                  | Marc Kleine-Budde           |
Industrial Linux Solutions        | Phone: +49-231-2826-924     |
Vertretung West/Dortmund          | Fax:   +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686  | http://www.pengutronix.de   |


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 259 bytes --]

^ permalink raw reply

* Re: [ethtool  3/3] ethtool: add ixgbevf support for register dump
From: Ben Hutchings @ 2013-08-29 20:57 UTC (permalink / raw)
  To: Jeff Kirsher; +Cc: Jacob Keller, netdev, gospo, sassmann
In-Reply-To: <1377648529-8297-3-git-send-email-jeffrey.t.kirsher@intel.com>

On Tue, 2013-08-27 at 17:08 -0700, Jeff Kirsher wrote:
> From: Jacob Keller <jacob.e.keller@intel.com>
> 
> This patch adds support for the ixgbevf driver, which previously was printing
> out as hex dump, and in the driver via printk. This patch corrects the
> implementation to have a new ixgbevf_reg_dump function that will format the
> register output in a more human readable format.
> 
> Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
> Tested-by: Stephen Ko <stephen.s.ko@intel.com>
> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>

Applied, but:

[...]
> --- /dev/null
> +++ b/ixgbevf.c
> @@ -0,0 +1,180 @@
> +/* Copyright (c) 2007 Intel Corporation */
[...]

I'm not sure whether to believe this date...

Ben.

-- 
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.

^ permalink raw reply

* Re: [PATCH 2/2] realtek: update devices to 3.11
From: Ben Hutchings @ 2013-08-29 20:52 UTC (permalink / raw)
  To: Peter Wu; +Cc: netdev, Francois Romieu
In-Reply-To: <1376429119-31380-3-git-send-email-lekensteyn@gmail.com>

On Tue, 2013-08-13 at 23:25 +0200, Peter Wu wrote:
> RTL8168_8111Bb/RTL8168_8111Bef is like RTL8111B/RTL8168B, RTL8100E and RTL8101E
> (datasheet revision 1.0 from 26 January 2006). Assume that RTL8101e is also
> similar (I may be very wrong at that though...).
> 
> Note that the scanning heuristics is the same as the r8169 module: newer devices
> with stronger masks come before the others. Perhaps the older 8139 cards should
> be appended to the list, after all r8169 chips.
> 
> Signed-off-by: Peter Wu <lekensteyn@gmail.com>
[...]

Applied, thanks.

Ben.

-- 
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.

^ permalink raw reply

* Re: [PATCH 1/2] realtek: convert to per-chip mask
From: Ben Hutchings @ 2013-08-29 20:51 UTC (permalink / raw)
  To: Peter Wu; +Cc: netdev, Francois Romieu
In-Reply-To: <1376429119-31380-2-git-send-email-lekensteyn@gmail.com>

On Tue, 2013-08-13 at 23:25 +0200, Peter Wu wrote:
> The previous HW_REVID macro did not make identifiers more readable
> (compared to hex values like 0x12345678) and only allowed for one static
> mask. To make it easier to update the chips list, let's use similar
> structures as r8169 and remove HW_REVID.
> 
> Names are removed and separated from the table and separated because the
> mac_version does not have to be unique.
> 
> While at it, change "RTL-xxxx" to "RTLxxxx" to match the names of
> Realtek and r8169 driver. Besides that, the only output change is when
> a chip is not recognized in which case "TxConfig" is now mentioned
> instead of "mask". Since the mask can be anything, the displayed word is
> not masked either.
> 
> Signed-off-by: Peter Wu <lekensteyn@gmail.com>
[...]

Applied, thanks.

Ben.

-- 
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.

^ permalink raw reply

* Re: [ethtool 1/3] ethtool: fix ixgbe 82598EB only registers
From: Ben Hutchings @ 2013-08-29 20:51 UTC (permalink / raw)
  To: Jeff Kirsher; +Cc: Jacob Keller, netdev, gospo, sassmann
In-Reply-To: <1377648529-8297-1-git-send-email-jeffrey.t.kirsher@intel.com>

On Tue, 2013-08-27 at 17:08 -0700, Jeff Kirsher wrote:
> From: Jacob Keller <jacob.e.keller@intel.com>
> 
> This patch fixes ixgbe_reg_dump to only display registers specific to the
> 82598EB part, as these registers display 0xDEADBEEF otherwise, and clutter up
> the register dump.
> 
> Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
> Tested-by: Phil Schmitt <phillip.j.schmitt@intel.com>
> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
> ---
>  ixgbe.c | 144 +++++++++++++++++++++++++++++++++-------------------------------
>  1 file changed, 75 insertions(+), 69 deletions(-)
> 
> diff --git a/ixgbe.c b/ixgbe.c
> index 9b005f2..89cb6be 100644
> --- a/ixgbe.c
> +++ b/ixgbe.c
[...]
> -	fprintf(stdout,
> -		"0x02F20: RDPROBE     (Rx Probe Mode Status)           0x%08X\n",
> -		regs_buff[1085]);
[...]

It looks like this removal really belongs to the next patch, which adds
it back with the mac_type < ixgbe_mac_X540 condition.

Ben.

-- 
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.

^ permalink raw reply

* Re: VLAN filtering/VLAN aware bridge problems
From: Vlad Yasevich @ 2013-08-29 20:45 UTC (permalink / raw)
  To: Stefan Priebe - Profihost AG; +Cc: David Miller, Linux Netdev List
In-Reply-To: <521F4393.1020907@profihost.ag>

On 08/29/2013 08:50 AM, Stefan Priebe - Profihost AG wrote:
> Hello,
>
> currently i'm running vanilla 3.8.8 kernel with some tap devices using
> VLANs on top of a bridge on top of a bond.
>
> This works fine and everything is great.
>
> Now i started to test 3.10.9 and all my VLANs stopped working no matter
> i disable or enable CONFIG_BRIDGE_VLAN_FILTERING.

Just enabling config option doesn't turn on the filtering behavior.

>
> The packets never reach the TAP device.
>
> Here is an output of ip a l (vlan 3021):

Can you provide output of brctl show?

>
> ip a l
> 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN
>      link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
>      inet 127.0.0.1/8 scope host lo
>         valid_lft forever preferred_lft forever
>      inet6 ::1/128 scope host
>         valid_lft forever preferred_lft forever
> 2: eth0: <BROADCAST,MULTICAST,PROMISC,SLAVE,UP,LOWER_UP> mtu 1500 qdisc
> mq master bond0 state UP qlen 1000
>      link/ether 00:25:90:84:de:a8 brd ff:ff:ff:ff:ff:ff
> 3: eth4: <BROADCAST,MULTICAST,SLAVE,UP,LOWER_UP> mtu 9000 qdisc mq
> master bond5 state UP qlen 10000
>      link/ether 90:e2:ba:33:45:0c brd ff:ff:ff:ff:ff:ff
> 4: eth1: <BROADCAST,MULTICAST,PROMISC,SLAVE,UP,LOWER_UP> mtu 1500 qdisc
> mq master bond0 state UP qlen 1000
>      link/ether 00:25:90:84:de:a8 brd ff:ff:ff:ff:ff:ff
> 5: eth2: <BROADCAST,MULTICAST,PROMISC,SLAVE,UP,LOWER_UP> mtu 1500 qdisc
> mq master bond1 state UP qlen 1000
>      link/ether 00:25:90:84:de:aa brd ff:ff:ff:ff:ff:ff
> 6: eth5: <BROADCAST,MULTICAST,SLAVE,UP,LOWER_UP> mtu 9000 qdisc mq
> master bond5 state UP qlen 10000
>      link/ether 90:e2:ba:33:45:0c brd ff:ff:ff:ff:ff:ff
> 7: eth3: <BROADCAST,MULTICAST,PROMISC,SLAVE,UP,LOWER_UP> mtu 1500 qdisc
> mq master bond1 state UP qlen 1000
>      link/ether 00:25:90:84:de:aa brd ff:ff:ff:ff:ff:ff
> 8: bond0: <BROADCAST,MULTICAST,MASTER,UP,LOWER_UP> mtu 1500 qdisc
> noqueue master vmbr0 state UP
>      link/ether 00:25:90:84:de:a8 brd ff:ff:ff:ff:ff:ff
>      inet6 fe80::225:90ff:fe84:dea8/64 scope link
>         valid_lft forever preferred_lft forever
> 9: bond1: <BROADCAST,MULTICAST,MASTER,UP,LOWER_UP> mtu 1500 qdisc
> noqueue master vmbr1 state UP
>      link/ether 00:25:90:84:de:aa brd ff:ff:ff:ff:ff:ff
>      inet6 fe80::225:90ff:fe84:deaa/64 scope link
>         valid_lft forever preferred_lft forever
> 10: vmbr0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue
> state UP
>      link/ether 00:25:90:84:de:a8 brd ff:ff:ff:ff:ff:ff
>      inet 178.250.9.30/25 brd 178.250.9.127 scope global vmbr0
>         valid_lft forever preferred_lft forever
>      inet6 fe80::225:90ff:fe84:dea8/64 scope link
>         valid_lft forever preferred_lft forever
> 11: vmbr1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue
> state UP
>      link/ether 00:25:90:84:de:aa brd ff:ff:ff:ff:ff:ff
>      inet6 fe80::225:90ff:fe84:deaa/64 scope link
>         valid_lft forever preferred_lft forever
> 12: bond5: <BROADCAST,MULTICAST,MASTER,UP,LOWER_UP> mtu 9000 qdisc
> noqueue state UP
>      link/ether 90:e2:ba:33:45:0c brd ff:ff:ff:ff:ff:ff
>      inet 10.255.0.30/24 brd 10.255.0.255 scope global bond5
>         valid_lft forever preferred_lft forever
>      inet6 fe80::92e2:baff:fe33:450c/64 scope link
>         valid_lft forever preferred_lft forever
> 15: vmbr1.3020@vmbr1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc
> noqueue master vmbr1v3020 state UP
>      link/ether 00:25:90:84:de:aa brd ff:ff:ff:ff:ff:ff
>      inet6 fe80::225:90ff:fe84:deaa/64 scope link
>         valid_lft forever preferred_lft forever
> 16: vmbr1v3020: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue
> state UP
>      link/ether 00:25:90:84:de:aa brd ff:ff:ff:ff:ff:ff
>      inet6 fe80::f036:92ff:fe40:7224/64 scope link
>         valid_lft forever preferred_lft forever
> 19: tap320i0: <BROADCAST,MULTICAST,PROMISC,UP,LOWER_UP> mtu 1500 qdisc
> htb master vmbr0 state UNKNOWN qlen 500
>      link/ether fe:fa:14:cc:75:b2 brd ff:ff:ff:ff:ff:ff
>      inet6 fe80::fcfa:14ff:fecc:75b2/64 scope link
>         valid_lft forever preferred_lft forever
> 20: tap320i1: <BROADCAST,MULTICAST,PROMISC,UP,LOWER_UP> mtu 1500 qdisc
> htb master vmbr1v3021 state UNKNOWN qlen 500
>      link/ether 8a:f3:9b:47:c7:88 brd ff:ff:ff:ff:ff:ff
>      inet6 fe80::88f3:9bff:fe47:c788/64 scope link
>         valid_lft forever preferred_lft forever
> 21: vmbr1.3021@vmbr1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc
> noqueue master vmbr1v3021 state UP
>      link/ether 00:25:90:84:de:aa brd ff:ff:ff:ff:ff:ff
>      inet6 fe80::225:90ff:fe84:deaa/64 scope link
>         valid_lft forever preferred_lft forever
> 22: vmbr1v3021: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue
> state UP
>      link/ether 00:25:90:84:de:aa brd ff:ff:ff:ff:ff:ff
>      inet6 fe80::9868:5eff:fe9d:bf56/64 scope link
>         valid_lft forever preferred_lft forever
>

I can only guess that the configuration based on the above data.  Can
you give a diagram of the config.

On the off chance that you are actually trying to configure vlan
filtering, can you give this patch a try (net-2.6 tree):

Author: Toshiaki Makita <makita.toshiaki@lab.ntt.co.jp>
Date:   Tue Aug 20 17:10:18 2013 +0900

     bridge: Use the correct bit length for bitmap functions in the VLAN 
code

I don't think it made it to stable yet.

Thanks
-vlad

> Greets,
> Stefan
>

^ permalink raw reply

* Re: [PATCH net-next 0/3] pf_packet updates
From: David Miller @ 2013-08-29 20:43 UTC (permalink / raw)
  To: dborkman; +Cc: netdev, amwang
In-Reply-To: <521EE81E.7030800@redhat.com>

From: Daniel Borkmann <dborkman@redhat.com>
Date: Thu, 29 Aug 2013 08:20:14 +0200

> On 08/29/2013 07:39 AM, David Miller wrote:
>> From: Daniel Borkmann <dborkman@redhat.com>
>> Date: Wed, 28 Aug 2013 22:13:08 +0200
>>
>>> Daniel Borkmann (3):
>>>    net: packet: add random fanout scheduler
>>>    net: packet: use reciprocal_divide in fanout_demux_hash
>>>    net: packet: document available fanout policies
>>
>> Please add the missing reciprocal_divide.h include to the second
>> patch, as per Eric Dumazet's feedback, and resubmit this series.
> 
> That is already the case in the first patch of the series. It adds:
> 
> ...
> +#include <linux/reciprocal_div.h>

Series applied, thanks Daniel.

^ permalink raw reply

* Re: [PATCH] xgmac: use bufsz not dma_buf_sz in rx_refill
From: David Miller @ 2013-08-29 20:38 UTC (permalink / raw)
  To: kmcmarti; +Cc: rob.herring, netdev
In-Reply-To: <20130829203523.GL8764@redacted.bos.redhat.com>

From: Kyle McMartin <kmcmarti@redhat.com>
Date: Thu, 29 Aug 2013 16:35:23 -0400

> On Thu, Aug 29, 2013 at 04:34:37PM -0400, David Miller wrote:
>> From: Kyle McMartin <kyle@redhat.com>
>> Date: Thu, 29 Aug 2013 16:11:51 -0400
>> 
>> > Noticed while debugging another issue that DMA debug turned up, looks
>> > like commit ef468d23 missed a case when switching to bufsz instead of
>> > priv->dma_buf_sz? (tbf, the whole handling of DMA buffers seems slightly
>> > suspect since we're not tracking the size, but trusting the hardware
>> > between map and unmap...)
>> > 
>> > Signed-off-by: Kyle McMartin <kyle@redhat.com>
>> 
>> Applied and queued up for -stable, thanks.
> 
> Heh, too fast David, Rob nak'd it. :)
> 
> Sorry about that.

If Rob had resubmitted his series in a timely manner this wouldn't
have happened.

I reverted.

^ permalink raw reply

* Re: [PATCH] xgmac: use bufsz not dma_buf_sz in rx_refill
From: David Miller @ 2013-08-29 20:38 UTC (permalink / raw)
  To: rob.herring; +Cc: kyle, netdev
In-Reply-To: <521FADFE.7040908@calxeda.com>

From: Rob Herring <rob.herring@calxeda.com>
Date: Thu, 29 Aug 2013 15:24:30 -0500

> On 08/29/2013 03:11 PM, Kyle McMartin wrote:
>> Noticed while debugging another issue that DMA debug turned up, looks
>> like commit ef468d23 missed a case when switching to bufsz instead of
>> priv->dma_buf_sz? (tbf, the whole handling of DMA buffers seems slightly
>> suspect since we're not tracking the size, but trusting the hardware
>> between map and unmap...)
> 
> Please see my patch series of fixes:
> 
> http://www.spinics.net/lists/netdev/msg248076.html

Which need to be resubmitted with feedback intergrated.

I knew your series existed, but Kyle submitted a fix in the correct
format meanwhile so I applied it.

^ permalink raw reply

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

From: Eric Dumazet <eric.dumazet@gmail.com>
Date: Thu, 29 Aug 2013 13:26:17 -0700

> Typical bufferbloat at the end of transfert :
> 
> [ 4547.051521] TCP: sk ffff88085825d180 cwnd 327 packets 3 rate 7575936000/srtt 1581
> [ 4547.052722] TCP: tcp_ack_update_rtt sk ffff88085825d180 seq_rtt 198 sack_rtt 4294967295
> [ 4547.052726] TCP: tcp_rtt_estimator sk ffff88085825d180 mrtt 198 srtt 1581
> [ 4547.052729] TCP: sk ffff88085825d180 cwnd 327 packets 1 rate 7575936000/srtt 1582
> [ 4547.053315] TCP: tcp_ack_update_rtt sk ffff88085825d180 seq_rtt 198 sack_rtt 4294967295
> [ 4547.053318] TCP: tcp_rtt_estimator sk ffff88085825d180 mrtt 198 srtt 1582
> [ 4547.053321] TCP: sk ffff88085825d180 cwnd 327 packets 0 rate 7575936000/srtt 1583
> 
> Maybe we could instead store a value corrected by the sk_pacing_rate
> 
> rate = (big_cwin * mss) / big_srtt
> 
> stored_rtt = rate / (big_cwin * mss)

No objections from me.

^ 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