Skip to content

Commit

Permalink
bql: Byte queue limits
Browse files Browse the repository at this point in the history
Networking stack support for byte queue limits, uses dynamic queue
limits library.  Byte queue limits are maintained per transmit queue,
and a dql structure has been added to netdev_queue structure for this
purpose.

Configuration of bql is in the tx-<n> sysfs directory for the queue
under the byte_queue_limits directory.  Configuration includes:
limit_min, bql minimum limit
limit_max, bql maximum limit
hold_time, bql slack hold time

Also under the directory are:
limit, current byte limit
inflight, current number of bytes on the queue

Signed-off-by: Tom Herbert <[email protected]>
Acked-by: Eric Dumazet <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
Tom Herbert authored and davem330 committed Nov 29, 2011
1 parent 927fbec commit 114cf58
Show file tree
Hide file tree
Showing 4 changed files with 172 additions and 9 deletions.
32 changes: 31 additions & 1 deletion include/linux/netdevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
#include <linux/rculist.h>
#include <linux/dmaengine.h>
#include <linux/workqueue.h>
#include <linux/dynamic_queue_limits.h>

#include <linux/ethtool.h>
#include <net/net_namespace.h>
Expand Down Expand Up @@ -541,7 +542,6 @@ struct netdev_queue {
*/
struct net_device *dev;
struct Qdisc *qdisc;
unsigned long state;
struct Qdisc *qdisc_sleeping;
#ifdef CONFIG_SYSFS
struct kobject kobj;
Expand All @@ -564,6 +564,12 @@ struct netdev_queue {
* (/sys/class/net/DEV/Q/trans_timeout)
*/
unsigned long trans_timeout;

unsigned long state;

#ifdef CONFIG_BQL
struct dql dql;
#endif
} ____cacheline_aligned_in_smp;

static inline int netdev_queue_numa_node_read(const struct netdev_queue *q)
Expand Down Expand Up @@ -1862,6 +1868,15 @@ static inline int netif_xmit_frozen_or_stopped(const struct netdev_queue *dev_qu
static inline void netdev_tx_sent_queue(struct netdev_queue *dev_queue,
unsigned int bytes)
{
#ifdef CONFIG_BQL
dql_queued(&dev_queue->dql, bytes);
if (unlikely(dql_avail(&dev_queue->dql) < 0)) {
set_bit(__QUEUE_STATE_STACK_XOFF, &dev_queue->state);
if (unlikely(dql_avail(&dev_queue->dql) >= 0))
clear_bit(__QUEUE_STATE_STACK_XOFF,
&dev_queue->state);
}
#endif
}

static inline void netdev_sent_queue(struct net_device *dev, unsigned int bytes)
Expand All @@ -1872,6 +1887,18 @@ static inline void netdev_sent_queue(struct net_device *dev, unsigned int bytes)
static inline void netdev_tx_completed_queue(struct netdev_queue *dev_queue,
unsigned pkts, unsigned bytes)
{
#ifdef CONFIG_BQL
if (likely(bytes)) {
dql_completed(&dev_queue->dql, bytes);
if (unlikely(test_bit(__QUEUE_STATE_STACK_XOFF,
&dev_queue->state) &&
dql_avail(&dev_queue->dql) >= 0)) {
if (test_and_clear_bit(__QUEUE_STATE_STACK_XOFF,
&dev_queue->state))
netif_schedule_queue(dev_queue);
}
}
#endif
}

static inline void netdev_completed_queue(struct net_device *dev,
Expand All @@ -1882,6 +1909,9 @@ static inline void netdev_completed_queue(struct net_device *dev,

static inline void netdev_tx_reset_queue(struct netdev_queue *q)
{
#ifdef CONFIG_BQL
dql_reset(&q->dql);
#endif
}

static inline void netdev_reset_queue(struct net_device *dev_queue)
Expand Down
6 changes: 6 additions & 0 deletions net/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,12 @@ config NETPRIO_CGROUP
Cgroup subsystem for use in assigning processes to network priorities on
a per-interface basis

config BQL
boolean
depends on SYSFS
select DQL
default y

config HAVE_BPF_JIT
bool

Expand Down
3 changes: 3 additions & 0 deletions net/core/dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -5470,6 +5470,9 @@ static void netdev_init_one_queue(struct net_device *dev,
queue->xmit_lock_owner = -1;
netdev_queue_numa_node_write(queue, NUMA_NO_NODE);
queue->dev = dev;
#ifdef CONFIG_BQL
dql_init(&queue->dql, HZ);
#endif
}

static int netif_alloc_netdev_queues(struct net_device *dev)
Expand Down
140 changes: 132 additions & 8 deletions net/core/net-sysfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <linux/wireless.h>
#include <linux/vmalloc.h>
#include <linux/export.h>
#include <linux/jiffies.h>
#include <net/wext.h>

#include "net-sysfs.h"
Expand Down Expand Up @@ -845,6 +846,116 @@ static ssize_t show_trans_timeout(struct netdev_queue *queue,
static struct netdev_queue_attribute queue_trans_timeout =
__ATTR(tx_timeout, S_IRUGO, show_trans_timeout, NULL);

#ifdef CONFIG_BQL
/*
* Byte queue limits sysfs structures and functions.
*/
static ssize_t bql_show(char *buf, unsigned int value)
{
return sprintf(buf, "%u\n", value);
}

static ssize_t bql_set(const char *buf, const size_t count,
unsigned int *pvalue)
{
unsigned int value;
int err;

if (!strcmp(buf, "max") || !strcmp(buf, "max\n"))
value = DQL_MAX_LIMIT;
else {
err = kstrtouint(buf, 10, &value);
if (err < 0)
return err;
if (value > DQL_MAX_LIMIT)
return -EINVAL;
}

*pvalue = value;

return count;
}

static ssize_t bql_show_hold_time(struct netdev_queue *queue,
struct netdev_queue_attribute *attr,
char *buf)
{
struct dql *dql = &queue->dql;

return sprintf(buf, "%u\n", jiffies_to_msecs(dql->slack_hold_time));
}

static ssize_t bql_set_hold_time(struct netdev_queue *queue,
struct netdev_queue_attribute *attribute,
const char *buf, size_t len)
{
struct dql *dql = &queue->dql;
unsigned value;
int err;

err = kstrtouint(buf, 10, &value);
if (err < 0)
return err;

dql->slack_hold_time = msecs_to_jiffies(value);

return len;
}

static struct netdev_queue_attribute bql_hold_time_attribute =
__ATTR(hold_time, S_IRUGO | S_IWUSR, bql_show_hold_time,
bql_set_hold_time);

static ssize_t bql_show_inflight(struct netdev_queue *queue,
struct netdev_queue_attribute *attr,
char *buf)
{
struct dql *dql = &queue->dql;

return sprintf(buf, "%u\n", dql->num_queued - dql->num_completed);
}

static struct netdev_queue_attribute bql_inflight_attribute =
__ATTR(inflight, S_IRUGO | S_IWUSR, bql_show_inflight, NULL);

#define BQL_ATTR(NAME, FIELD) \
static ssize_t bql_show_ ## NAME(struct netdev_queue *queue, \
struct netdev_queue_attribute *attr, \
char *buf) \
{ \
return bql_show(buf, queue->dql.FIELD); \
} \
\
static ssize_t bql_set_ ## NAME(struct netdev_queue *queue, \
struct netdev_queue_attribute *attr, \
const char *buf, size_t len) \
{ \
return bql_set(buf, len, &queue->dql.FIELD); \
} \
\
static struct netdev_queue_attribute bql_ ## NAME ## _attribute = \
__ATTR(NAME, S_IRUGO | S_IWUSR, bql_show_ ## NAME, \
bql_set_ ## NAME);

BQL_ATTR(limit, limit)
BQL_ATTR(limit_max, max_limit)
BQL_ATTR(limit_min, min_limit)

static struct attribute *dql_attrs[] = {
&bql_limit_attribute.attr,
&bql_limit_max_attribute.attr,
&bql_limit_min_attribute.attr,
&bql_hold_time_attribute.attr,
&bql_inflight_attribute.attr,
NULL
};

static struct attribute_group dql_group = {
.name = "byte_queue_limits",
.attrs = dql_attrs,
};
#endif /* CONFIG_BQL */

#ifdef CONFIG_XPS
static inline unsigned int get_netdev_queue_index(struct netdev_queue *queue)
{
Expand Down Expand Up @@ -1096,17 +1207,17 @@ static struct attribute *netdev_queue_default_attrs[] = {
NULL
};

#ifdef CONFIG_XPS
static void netdev_queue_release(struct kobject *kobj)
{
struct netdev_queue *queue = to_netdev_queue(kobj);

#ifdef CONFIG_XPS
xps_queue_release(queue);
#endif

memset(kobj, 0, sizeof(*kobj));
dev_put(queue->dev);
}
#endif /* CONFIG_XPS */

static struct kobj_type netdev_queue_ktype = {
.sysfs_ops = &netdev_queue_sysfs_ops,
Expand All @@ -1125,14 +1236,21 @@ static int netdev_queue_add_kobject(struct net_device *net, int index)
kobj->kset = net->queues_kset;
error = kobject_init_and_add(kobj, &netdev_queue_ktype, NULL,
"tx-%u", index);
if (error) {
kobject_put(kobj);
return error;
}
if (error)
goto exit;

#ifdef CONFIG_BQL
error = sysfs_create_group(kobj, &dql_group);
if (error)
goto exit;
#endif

kobject_uevent(kobj, KOBJ_ADD);
dev_hold(queue->dev);

return 0;
exit:
kobject_put(kobj);
return error;
}
#endif /* CONFIG_SYSFS */
Expand All @@ -1152,8 +1270,14 @@ netdev_queue_update_kobjects(struct net_device *net, int old_num, int new_num)
}
}

while (--i >= new_num)
kobject_put(&net->_tx[i].kobj);
while (--i >= new_num) {
struct netdev_queue *queue = net->_tx + i;

#ifdef CONFIG_BQL
sysfs_remove_group(&queue->kobj, &dql_group);
#endif
kobject_put(&queue->kobj);
}

return error;
#else
Expand Down

0 comments on commit 114cf58

Please sign in to comment.