From 59e294065ddee7074af91e4f5e12e6095eb1135b Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Fri, 30 Dec 2011 10:34:03 -0300 Subject: Bluetooth: Rename extfeatures This patch renames hdev->extfeatures to hdev->host_features since it holds the extended features Page 1 (aka host features). Signed-off-by: Andre Guedes Acked-by: Marcel Holtmann Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/hci_core.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 5e2e9845849..ea9231f4935 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -127,7 +127,7 @@ struct hci_dev { __u8 major_class; __u8 minor_class; __u8 features[8]; - __u8 extfeatures[8]; + __u8 host_features[8]; __u8 commands[64]; __u8 ssp_mode; __u8 hci_ver; @@ -676,7 +676,7 @@ void hci_conn_del_sysfs(struct hci_conn *conn); #define lmp_le_capable(dev) ((dev)->features[4] & LMP_LE) /* ----- Extended LMP capabilities ----- */ -#define lmp_host_le_capable(dev) ((dev)->extfeatures[0] & LMP_HOST_LE) +#define lmp_host_le_capable(dev) ((dev)->host_features[0] & LMP_HOST_LE) /* ----- HCI protocols ----- */ static inline int hci_proto_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, -- cgit v1.2.3 From c8991362a0d3cf317dfbfb6cb946607870654e6d Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Tue, 10 Jan 2012 22:36:35 +0000 Subject: inet_diag: Rename inet_diag_req into inet_diag_req_v2 Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- include/linux/inet_diag.h | 12 ++++++------ net/dccp/diag.c | 4 ++-- net/ipv4/inet_diag.c | 34 +++++++++++++++++----------------- net/ipv4/tcp_diag.c | 4 ++-- net/ipv4/udp_diag.c | 14 +++++++------- 5 files changed, 34 insertions(+), 34 deletions(-) (limited to 'include') diff --git a/include/linux/inet_diag.h b/include/linux/inet_diag.h index 34e8d52c192..a5b7e910eea 100644 --- a/include/linux/inet_diag.h +++ b/include/linux/inet_diag.h @@ -34,7 +34,7 @@ struct inet_diag_req_compat { __u32 idiag_dbs; /* Tables to dump (NI) */ }; -struct inet_diag_req { +struct inet_diag_req_v2 { __u8 sdiag_family; __u8 sdiag_protocol; __u8 idiag_ext; @@ -143,12 +143,12 @@ struct netlink_callback; struct inet_diag_handler { void (*dump)(struct sk_buff *skb, struct netlink_callback *cb, - struct inet_diag_req *r, + struct inet_diag_req_v2 *r, struct nlattr *bc); int (*dump_one)(struct sk_buff *in_skb, const struct nlmsghdr *nlh, - struct inet_diag_req *req); + struct inet_diag_req_v2 *req); void (*idiag_get_info)(struct sock *sk, struct inet_diag_msg *r, @@ -158,15 +158,15 @@ struct inet_diag_handler { struct inet_connection_sock; int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk, - struct sk_buff *skb, struct inet_diag_req *req, + struct sk_buff *skb, struct inet_diag_req_v2 *req, u32 pid, u32 seq, u16 nlmsg_flags, const struct nlmsghdr *unlh); void inet_diag_dump_icsk(struct inet_hashinfo *h, struct sk_buff *skb, - struct netlink_callback *cb, struct inet_diag_req *r, + struct netlink_callback *cb, struct inet_diag_req_v2 *r, struct nlattr *bc); int inet_diag_dump_one_icsk(struct inet_hashinfo *hashinfo, struct sk_buff *in_skb, const struct nlmsghdr *nlh, - struct inet_diag_req *req); + struct inet_diag_req_v2 *req); int inet_diag_bc_sk(const struct nlattr *_bc, struct sock *sk); diff --git a/net/dccp/diag.c b/net/dccp/diag.c index 8f162575337..028fc43aacb 100644 --- a/net/dccp/diag.c +++ b/net/dccp/diag.c @@ -49,13 +49,13 @@ static void dccp_diag_get_info(struct sock *sk, struct inet_diag_msg *r, } static void dccp_diag_dump(struct sk_buff *skb, struct netlink_callback *cb, - struct inet_diag_req *r, struct nlattr *bc) + struct inet_diag_req_v2 *r, struct nlattr *bc) { inet_diag_dump_icsk(&dccp_hashinfo, skb, cb, r, bc); } static int dccp_diag_dump_one(struct sk_buff *in_skb, const struct nlmsghdr *nlh, - struct inet_diag_req *req) + struct inet_diag_req_v2 *req) { return inet_diag_dump_one_icsk(&dccp_hashinfo, in_skb, nlh, req); } diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c index 2240a8e8c44..cf23a7cacdd 100644 --- a/net/ipv4/inet_diag.c +++ b/net/ipv4/inet_diag.c @@ -71,7 +71,7 @@ static inline void inet_diag_unlock_handler( } int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk, - struct sk_buff *skb, struct inet_diag_req *req, + struct sk_buff *skb, struct inet_diag_req_v2 *req, u32 pid, u32 seq, u16 nlmsg_flags, const struct nlmsghdr *unlh) { @@ -193,7 +193,7 @@ nlmsg_failure: EXPORT_SYMBOL_GPL(inet_sk_diag_fill); static int inet_csk_diag_fill(struct sock *sk, - struct sk_buff *skb, struct inet_diag_req *req, + struct sk_buff *skb, struct inet_diag_req_v2 *req, u32 pid, u32 seq, u16 nlmsg_flags, const struct nlmsghdr *unlh) { @@ -202,7 +202,7 @@ static int inet_csk_diag_fill(struct sock *sk, } static int inet_twsk_diag_fill(struct inet_timewait_sock *tw, - struct sk_buff *skb, struct inet_diag_req *req, + struct sk_buff *skb, struct inet_diag_req_v2 *req, u32 pid, u32 seq, u16 nlmsg_flags, const struct nlmsghdr *unlh) { @@ -253,7 +253,7 @@ nlmsg_failure: } static int sk_diag_fill(struct sock *sk, struct sk_buff *skb, - struct inet_diag_req *r, u32 pid, u32 seq, u16 nlmsg_flags, + struct inet_diag_req_v2 *r, u32 pid, u32 seq, u16 nlmsg_flags, const struct nlmsghdr *unlh) { if (sk->sk_state == TCP_TIME_WAIT) @@ -264,7 +264,7 @@ static int sk_diag_fill(struct sock *sk, struct sk_buff *skb, } int inet_diag_dump_one_icsk(struct inet_hashinfo *hashinfo, struct sk_buff *in_skb, - const struct nlmsghdr *nlh, struct inet_diag_req *req) + const struct nlmsghdr *nlh, struct inet_diag_req_v2 *req) { int err; struct sock *sk; @@ -333,7 +333,7 @@ EXPORT_SYMBOL_GPL(inet_diag_dump_one_icsk); static int inet_diag_get_exact(struct sk_buff *in_skb, const struct nlmsghdr *nlh, - struct inet_diag_req *req) + struct inet_diag_req_v2 *req) { const struct inet_diag_handler *handler; int err; @@ -540,7 +540,7 @@ static int inet_diag_bc_audit(const void *bytecode, int bytecode_len) static int inet_csk_diag_dump(struct sock *sk, struct sk_buff *skb, struct netlink_callback *cb, - struct inet_diag_req *r, + struct inet_diag_req_v2 *r, const struct nlattr *bc) { if (!inet_diag_bc_sk(bc, sk)) @@ -554,7 +554,7 @@ static int inet_csk_diag_dump(struct sock *sk, static int inet_twsk_diag_dump(struct inet_timewait_sock *tw, struct sk_buff *skb, struct netlink_callback *cb, - struct inet_diag_req *r, + struct inet_diag_req_v2 *r, const struct nlattr *bc) { if (bc != NULL) { @@ -639,7 +639,7 @@ nlmsg_failure: static int inet_diag_dump_reqs(struct sk_buff *skb, struct sock *sk, struct netlink_callback *cb, - struct inet_diag_req *r, + struct inet_diag_req_v2 *r, const struct nlattr *bc) { struct inet_diag_entry entry; @@ -721,7 +721,7 @@ out: } void inet_diag_dump_icsk(struct inet_hashinfo *hashinfo, struct sk_buff *skb, - struct netlink_callback *cb, struct inet_diag_req *r, struct nlattr *bc) + struct netlink_callback *cb, struct inet_diag_req_v2 *r, struct nlattr *bc) { int i, num; int s_i, s_num; @@ -872,7 +872,7 @@ out: EXPORT_SYMBOL_GPL(inet_diag_dump_icsk); static int __inet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb, - struct inet_diag_req *r, struct nlattr *bc) + struct inet_diag_req_v2 *r, struct nlattr *bc) { const struct inet_diag_handler *handler; @@ -887,12 +887,12 @@ static int __inet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb, static int inet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb) { struct nlattr *bc = NULL; - int hdrlen = sizeof(struct inet_diag_req); + int hdrlen = sizeof(struct inet_diag_req_v2); if (nlmsg_attrlen(cb->nlh, hdrlen)) bc = nlmsg_find_attr(cb->nlh, hdrlen, INET_DIAG_REQ_BYTECODE); - return __inet_diag_dump(skb, cb, (struct inet_diag_req *)NLMSG_DATA(cb->nlh), bc); + return __inet_diag_dump(skb, cb, (struct inet_diag_req_v2 *)NLMSG_DATA(cb->nlh), bc); } static inline int inet_diag_type2proto(int type) @@ -910,7 +910,7 @@ static inline int inet_diag_type2proto(int type) static int inet_diag_dump_compat(struct sk_buff *skb, struct netlink_callback *cb) { struct inet_diag_req_compat *rc = NLMSG_DATA(cb->nlh); - struct inet_diag_req req; + struct inet_diag_req_v2 req; struct nlattr *bc = NULL; int hdrlen = sizeof(struct inet_diag_req_compat); @@ -930,7 +930,7 @@ static int inet_diag_get_exact_compat(struct sk_buff *in_skb, const struct nlmsghdr *nlh) { struct inet_diag_req_compat *rc = NLMSG_DATA(nlh); - struct inet_diag_req req; + struct inet_diag_req_v2 req; req.sdiag_family = rc->idiag_family; req.sdiag_protocol = inet_diag_type2proto(nlh->nlmsg_type); @@ -970,7 +970,7 @@ static int inet_diag_rcv_msg_compat(struct sk_buff *skb, struct nlmsghdr *nlh) static int inet_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h) { - int hdrlen = sizeof(struct inet_diag_req); + int hdrlen = sizeof(struct inet_diag_req_v2); if (nlmsg_len(h) < hdrlen) return -EINVAL; @@ -990,7 +990,7 @@ static int inet_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h) inet_diag_dump, NULL, 0); } - return inet_diag_get_exact(skb, h, (struct inet_diag_req *)NLMSG_DATA(h)); + return inet_diag_get_exact(skb, h, (struct inet_diag_req_v2 *)NLMSG_DATA(h)); } static struct sock_diag_handler inet_diag_handler = { diff --git a/net/ipv4/tcp_diag.c b/net/ipv4/tcp_diag.c index 8cd357a8be7..ed3f2ad42e0 100644 --- a/net/ipv4/tcp_diag.c +++ b/net/ipv4/tcp_diag.c @@ -35,13 +35,13 @@ static void tcp_diag_get_info(struct sock *sk, struct inet_diag_msg *r, } static void tcp_diag_dump(struct sk_buff *skb, struct netlink_callback *cb, - struct inet_diag_req *r, struct nlattr *bc) + struct inet_diag_req_v2 *r, struct nlattr *bc) { inet_diag_dump_icsk(&tcp_hashinfo, skb, cb, r, bc); } static int tcp_diag_dump_one(struct sk_buff *in_skb, const struct nlmsghdr *nlh, - struct inet_diag_req *req) + struct inet_diag_req_v2 *req) { return inet_diag_dump_one_icsk(&tcp_hashinfo, in_skb, nlh, req); } diff --git a/net/ipv4/udp_diag.c b/net/ipv4/udp_diag.c index 69f8a7ca63d..e5e18cb8a58 100644 --- a/net/ipv4/udp_diag.c +++ b/net/ipv4/udp_diag.c @@ -19,7 +19,7 @@ #include static int sk_diag_dump(struct sock *sk, struct sk_buff *skb, - struct netlink_callback *cb, struct inet_diag_req *req, + struct netlink_callback *cb, struct inet_diag_req_v2 *req, struct nlattr *bc) { if (!inet_diag_bc_sk(bc, sk)) @@ -30,7 +30,7 @@ static int sk_diag_dump(struct sock *sk, struct sk_buff *skb, } static int udp_dump_one(struct udp_table *tbl, struct sk_buff *in_skb, - const struct nlmsghdr *nlh, struct inet_diag_req *req) + const struct nlmsghdr *nlh, struct inet_diag_req_v2 *req) { int err = -EINVAL; struct sock *sk; @@ -88,7 +88,7 @@ out_nosk: } static void udp_dump(struct udp_table *table, struct sk_buff *skb, struct netlink_callback *cb, - struct inet_diag_req *r, struct nlattr *bc) + struct inet_diag_req_v2 *r, struct nlattr *bc) { int num, s_num, slot, s_slot; @@ -136,13 +136,13 @@ done: } static void udp_diag_dump(struct sk_buff *skb, struct netlink_callback *cb, - struct inet_diag_req *r, struct nlattr *bc) + struct inet_diag_req_v2 *r, struct nlattr *bc) { udp_dump(&udp_table, skb, cb, r, bc); } static int udp_diag_dump_one(struct sk_buff *in_skb, const struct nlmsghdr *nlh, - struct inet_diag_req *req) + struct inet_diag_req_v2 *req) { return udp_dump_one(&udp_table, in_skb, nlh, req); } @@ -154,13 +154,13 @@ static const struct inet_diag_handler udp_diag_handler = { }; static void udplite_diag_dump(struct sk_buff *skb, struct netlink_callback *cb, - struct inet_diag_req *r, struct nlattr *bc) + struct inet_diag_req_v2 *r, struct nlattr *bc) { udp_dump(&udplite_table, skb, cb, r, bc); } static int udplite_diag_dump_one(struct sk_buff *in_skb, const struct nlmsghdr *nlh, - struct inet_diag_req *req) + struct inet_diag_req_v2 *req) { return udp_dump_one(&udplite_table, in_skb, nlh, req); } -- cgit v1.2.3 From 3b09c84cb622ffbcdb5d541986b1eaf7d5812602 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Tue, 10 Jan 2012 22:37:26 +0000 Subject: inet_diag: Rename inet_diag_req_compat into inet_diag_req Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- include/linux/inet_diag.h | 2 +- net/ipv4/inet_diag.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/include/linux/inet_diag.h b/include/linux/inet_diag.h index a5b7e910eea..f1362b5447f 100644 --- a/include/linux/inet_diag.h +++ b/include/linux/inet_diag.h @@ -22,7 +22,7 @@ struct inet_diag_sockid { /* Request structure */ -struct inet_diag_req_compat { +struct inet_diag_req { __u8 idiag_family; /* Family of addresses. */ __u8 idiag_src_len; __u8 idiag_dst_len; diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c index cf23a7cacdd..fcf281819cd 100644 --- a/net/ipv4/inet_diag.c +++ b/net/ipv4/inet_diag.c @@ -909,10 +909,10 @@ static inline int inet_diag_type2proto(int type) static int inet_diag_dump_compat(struct sk_buff *skb, struct netlink_callback *cb) { - struct inet_diag_req_compat *rc = NLMSG_DATA(cb->nlh); + struct inet_diag_req *rc = NLMSG_DATA(cb->nlh); struct inet_diag_req_v2 req; struct nlattr *bc = NULL; - int hdrlen = sizeof(struct inet_diag_req_compat); + int hdrlen = sizeof(struct inet_diag_req); req.sdiag_family = AF_UNSPEC; /* compatibility */ req.sdiag_protocol = inet_diag_type2proto(cb->nlh->nlmsg_type); @@ -929,7 +929,7 @@ static int inet_diag_dump_compat(struct sk_buff *skb, struct netlink_callback *c static int inet_diag_get_exact_compat(struct sk_buff *in_skb, const struct nlmsghdr *nlh) { - struct inet_diag_req_compat *rc = NLMSG_DATA(nlh); + struct inet_diag_req *rc = NLMSG_DATA(nlh); struct inet_diag_req_v2 req; req.sdiag_family = rc->idiag_family; @@ -943,7 +943,7 @@ static int inet_diag_get_exact_compat(struct sk_buff *in_skb, static int inet_diag_rcv_msg_compat(struct sk_buff *skb, struct nlmsghdr *nlh) { - int hdrlen = sizeof(struct inet_diag_req_compat); + int hdrlen = sizeof(struct inet_diag_req); if (nlh->nlmsg_type >= INET_DIAG_GETSOCK_MAX || nlmsg_len(nlh) < hdrlen) -- cgit v1.2.3 From eb8a54a78e974e1af3e17fa38bb74d3747c5c1bd Mon Sep 17 00:00:00 2001 From: Timur Tabi Date: Thu, 12 Jan 2012 15:23:04 -0800 Subject: phylib: introduce mdiobus_alloc_size() Introduce function mdiobus_alloc_size() as an alternative to mdiobus_alloc(). Most callers of mdiobus_alloc() also allocate a private data structure, and then manually point bus->priv to this object. mdiobus_alloc_size() combines the two operations into one, which simplifies memory management. The original mdiobus_alloc() now just calls mdiobus_alloc_size(0). Signed-off-by: Timur Tabi Signed-off-by: David S. Miller --- drivers/net/phy/mdio_bus.c | 24 +++++++++++++++++++----- include/linux/phy.h | 7 ++++++- 2 files changed, 25 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index 6c58da2b882..88cc5db9aff 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -37,22 +37,36 @@ #include /** - * mdiobus_alloc - allocate a mii_bus structure + * mdiobus_alloc_size - allocate a mii_bus structure * * Description: called by a bus driver to allocate an mii_bus * structure to fill in. + * + * 'size' is an an extra amount of memory to allocate for private storage. + * If non-zero, then bus->priv is points to that memory. */ -struct mii_bus *mdiobus_alloc(void) +struct mii_bus *mdiobus_alloc_size(size_t size) { struct mii_bus *bus; + size_t aligned_size = ALIGN(sizeof(*bus), NETDEV_ALIGN); + size_t alloc_size; + + /* If we alloc extra space, it should be aligned */ + if (size) + alloc_size = aligned_size + size; + else + alloc_size = sizeof(*bus); - bus = kzalloc(sizeof(*bus), GFP_KERNEL); - if (bus != NULL) + bus = kzalloc(alloc_size, GFP_KERNEL); + if (bus) { bus->state = MDIOBUS_ALLOCATED; + if (size) + bus->priv = (void *)bus + aligned_size; + } return bus; } -EXPORT_SYMBOL(mdiobus_alloc); +EXPORT_SYMBOL(mdiobus_alloc_size); /** * mdiobus_release - mii_bus device release callback diff --git a/include/linux/phy.h b/include/linux/phy.h index 79f337c4738..c599f7eca1e 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -129,7 +129,12 @@ struct mii_bus { }; #define to_mii_bus(d) container_of(d, struct mii_bus, dev) -struct mii_bus *mdiobus_alloc(void); +struct mii_bus *mdiobus_alloc_size(size_t); +static inline struct mii_bus *mdiobus_alloc(void) +{ + return mdiobus_alloc_size(0); +} + int mdiobus_register(struct mii_bus *bus); void mdiobus_unregister(struct mii_bus *bus); void mdiobus_free(struct mii_bus *bus); -- cgit v1.2.3 From ddecf0f4db44ef94847a62d6ecf74456b4dcc66f Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 6 Jan 2012 06:31:44 +0000 Subject: net_sched: sfq: add optional RED on top of SFQ Adds an optional Random Early Detection on each SFQ flow queue. Traditional SFQ limits count of packets, while RED permits to also control number of bytes per flow, and adds ECN capability as well. 1) We dont handle the idle time management in this RED implementation, since each 'new flow' begins with a null qavg. We really want to address backlogged flows. 2) if headdrop is selected, we try to ecn mark first packet instead of currently enqueued packet. This gives faster feedback for tcp flows compared to traditional RED [ marking the last packet in queue ] Example of use : tc qdisc add dev $DEV parent 1:1 handle 10: est 1sec 4sec sfq \ limit 3000 headdrop flows 512 divisor 16384 \ redflowlimit 100000 min 8000 max 60000 probability 0.20 ecn qdisc sfq 10: parent 1:1 limit 3000p quantum 1514b depth 127 headdrop flows 512/16384 divisor 16384 ewma 6 min 8000b max 60000b probability 0.2 ecn prob_mark 0 prob_mark_head 4876 prob_drop 6131 forced_mark 0 forced_mark_head 0 forced_drop 0 Sent 1175211782 bytes 777537 pkt (dropped 6131, overlimits 11007 requeues 0) rate 99483Kbit 8219pps backlog 689392b 456p requeues 0 In this test, with 64 netperf TCP_STREAM sessions, 50% using ECN enabled flows, we can see number of packets CE marked is smaller than number of drops (for non ECN flows) If same test is run, without RED, we can check backlog is much bigger. qdisc sfq 10: parent 1:1 limit 3000p quantum 1514b depth 127 headdrop flows 512/16384 divisor 16384 Sent 1148683617 bytes 795006 pkt (dropped 0, overlimits 0 requeues 0) rate 98429Kbit 8521pps backlog 1221290b 841p requeues 0 Signed-off-by: Eric Dumazet CC: Stephen Hemminger CC: Dave Taht Tested-by: Dave Taht Signed-off-by: David S. Miller --- include/linux/pkt_sched.h | 20 +++++++ include/net/red.h | 3 +- net/sched/sch_sfq.c | 146 +++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 152 insertions(+), 17 deletions(-) (limited to 'include') diff --git a/include/linux/pkt_sched.h b/include/linux/pkt_sched.h index 8f1b928f777..0d5b79365d0 100644 --- a/include/linux/pkt_sched.h +++ b/include/linux/pkt_sched.h @@ -162,10 +162,30 @@ struct tc_sfq_qopt { unsigned flows; /* Maximal number of flows */ }; +struct tc_sfqred_stats { + __u32 prob_drop; /* Early drops, below max threshold */ + __u32 forced_drop; /* Early drops, after max threshold */ + __u32 prob_mark; /* Marked packets, below max threshold */ + __u32 forced_mark; /* Marked packets, after max threshold */ + __u32 prob_mark_head; /* Marked packets, below max threshold */ + __u32 forced_mark_head;/* Marked packets, after max threshold */ +}; + struct tc_sfq_qopt_v1 { struct tc_sfq_qopt v0; unsigned int depth; /* max number of packets per flow */ unsigned int headdrop; +/* SFQRED parameters */ + __u32 limit; /* HARD maximal flow queue length (bytes) */ + __u32 qth_min; /* Min average length threshold (bytes) */ + __u32 qth_max; /* Max average length threshold (bytes) */ + unsigned char Wlog; /* log(W) */ + unsigned char Plog; /* log(P_max/(qth_max-qth_min)) */ + unsigned char Scell_log; /* cell size for idle damping */ + unsigned char flags; + __u32 max_P; /* probability, high resolution */ +/* SFQRED stats */ + struct tc_sfqred_stats stats; }; diff --git a/include/net/red.h b/include/net/red.h index baab385a473..28068ec614b 100644 --- a/include/net/red.h +++ b/include/net/red.h @@ -199,7 +199,8 @@ static inline void red_set_parms(struct red_parms *p, p->Scell_log = Scell_log; p->Scell_max = (255 << Scell_log); - memcpy(p->Stab, stab, sizeof(p->Stab)); + if (stab) + memcpy(p->Stab, stab, sizeof(p->Stab)); } static inline int red_is_idling(const struct red_vars *v) diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c index 0a7964009e8..67494aef9ac 100644 --- a/net/sched/sch_sfq.c +++ b/net/sched/sch_sfq.c @@ -24,6 +24,7 @@ #include #include #include +#include /* Stochastic Fairness Queuing algorithm. @@ -108,24 +109,30 @@ struct sfq_slot { struct sfq_head dep; /* anchor in dep[] chains */ unsigned short hash; /* hash value (index in ht[]) */ short allot; /* credit for this slot */ + + unsigned int backlog; + struct red_vars vars; }; struct sfq_sched_data { /* frequently used fields */ int limit; /* limit of total number of packets in this qdisc */ unsigned int divisor; /* number of slots in hash table */ - unsigned int maxflows; /* number of flows in flows array */ - int headdrop; - int maxdepth; /* limit of packets per flow */ + u8 headdrop; + u8 maxdepth; /* limit of packets per flow */ u32 perturbation; - struct tcf_proto *filter_list; - sfq_index cur_depth; /* depth of longest slot */ + u8 cur_depth; /* depth of longest slot */ + u8 flags; unsigned short scaled_quantum; /* SFQ_ALLOT_SIZE(quantum) */ - struct sfq_slot *tail; /* current slot in round */ + struct tcf_proto *filter_list; sfq_index *ht; /* Hash table ('divisor' slots) */ struct sfq_slot *slots; /* Flows table ('maxflows' entries) */ + struct red_parms *red_parms; + struct tc_sfqred_stats stats; + struct sfq_slot *tail; /* current slot in round */ + struct sfq_head dep[SFQ_MAX_DEPTH + 1]; /* Linked lists of slots, indexed by depth * dep[0] : list of unused flows @@ -133,6 +140,7 @@ struct sfq_sched_data { * dep[X] : list of flows with X packets */ + unsigned int maxflows; /* number of flows in flows array */ int perturb_period; unsigned int quantum; /* Allotment per round: MUST BE >= MTU */ struct timer_list perturb_timer; @@ -321,6 +329,7 @@ static unsigned int sfq_drop(struct Qdisc *sch) drop: skb = q->headdrop ? slot_dequeue_head(slot) : slot_dequeue_tail(slot); len = qdisc_pkt_len(skb); + slot->backlog -= len; sfq_dec(q, x); kfree_skb(skb); sch->q.qlen--; @@ -341,6 +350,23 @@ drop: return 0; } +/* Is ECN parameter configured */ +static int sfq_prob_mark(const struct sfq_sched_data *q) +{ + return q->flags & TC_RED_ECN; +} + +/* Should packets over max threshold just be marked */ +static int sfq_hard_mark(const struct sfq_sched_data *q) +{ + return (q->flags & (TC_RED_ECN | TC_RED_HARDDROP)) == TC_RED_ECN; +} + +static int sfq_headdrop(const struct sfq_sched_data *q) +{ + return q->headdrop; +} + static int sfq_enqueue(struct sk_buff *skb, struct Qdisc *sch) { @@ -349,6 +375,8 @@ sfq_enqueue(struct sk_buff *skb, struct Qdisc *sch) sfq_index x, qlen; struct sfq_slot *slot; int uninitialized_var(ret); + struct sk_buff *head; + int delta; hash = sfq_classify(skb, sch, &ret); if (hash == 0) { @@ -368,24 +396,75 @@ sfq_enqueue(struct sk_buff *skb, struct Qdisc *sch) q->ht[hash] = x; slot = &q->slots[x]; slot->hash = hash; + slot->backlog = 0; /* should already be 0 anyway... */ + red_set_vars(&slot->vars); + goto enqueue; } + if (q->red_parms) { + slot->vars.qavg = red_calc_qavg_no_idle_time(q->red_parms, + &slot->vars, + slot->backlog); + switch (red_action(q->red_parms, + &slot->vars, + slot->vars.qavg)) { + case RED_DONT_MARK: + break; - if (slot->qlen >= q->maxdepth) { - struct sk_buff *head; + case RED_PROB_MARK: + sch->qstats.overlimits++; + if (sfq_prob_mark(q)) { + /* We know we have at least one packet in queue */ + if (sfq_headdrop(q) && + INET_ECN_set_ce(slot->skblist_next)) { + q->stats.prob_mark_head++; + break; + } + if (INET_ECN_set_ce(skb)) { + q->stats.prob_mark++; + break; + } + } + q->stats.prob_drop++; + goto congestion_drop; + + case RED_HARD_MARK: + sch->qstats.overlimits++; + if (sfq_hard_mark(q)) { + /* We know we have at least one packet in queue */ + if (sfq_headdrop(q) && + INET_ECN_set_ce(slot->skblist_next)) { + q->stats.forced_mark_head++; + break; + } + if (INET_ECN_set_ce(skb)) { + q->stats.forced_mark++; + break; + } + } + q->stats.forced_drop++; + goto congestion_drop; + } + } - if (!q->headdrop) + if (slot->qlen >= q->maxdepth) { +congestion_drop: + if (!sfq_headdrop(q)) return qdisc_drop(skb, sch); + /* We know we have at least one packet in queue */ head = slot_dequeue_head(slot); - sch->qstats.backlog -= qdisc_pkt_len(head); + delta = qdisc_pkt_len(head) - qdisc_pkt_len(skb); + sch->qstats.backlog -= delta; + slot->backlog -= delta; qdisc_drop(head, sch); - sch->qstats.backlog += qdisc_pkt_len(skb); slot_queue_add(slot, skb); return NET_XMIT_CN; } +enqueue: sch->qstats.backlog += qdisc_pkt_len(skb); + slot->backlog += qdisc_pkt_len(skb); slot_queue_add(slot, skb); sfq_inc(q, x); if (slot->qlen == 1) { /* The flow is new */ @@ -396,6 +475,7 @@ sfq_enqueue(struct sk_buff *skb, struct Qdisc *sch) slot->next = q->tail->next; q->tail->next = x; } + /* We could use a bigger initial quantum for new flows */ slot->allot = q->scaled_quantum; } if (++sch->q.qlen <= q->limit) @@ -439,7 +519,7 @@ next_slot: qdisc_bstats_update(sch, skb); sch->q.qlen--; sch->qstats.backlog -= qdisc_pkt_len(skb); - + slot->backlog -= qdisc_pkt_len(skb); /* Is the slot empty? */ if (slot->qlen == 0) { q->ht[slot->hash] = SFQ_EMPTY_SLOT; @@ -490,6 +570,8 @@ static void sfq_rehash(struct Qdisc *sch) sfq_dec(q, i); __skb_queue_tail(&list, skb); } + slot->backlog = 0; + red_set_vars(&slot->vars); q->ht[slot->hash] = SFQ_EMPTY_SLOT; } q->tail = NULL; @@ -514,6 +596,11 @@ drop: sch->qstats.backlog -= qdisc_pkt_len(skb); if (slot->qlen >= q->maxdepth) goto drop; slot_queue_add(slot, skb); + if (q->red_parms) + slot->vars.qavg = red_calc_qavg(q->red_parms, + &slot->vars, + slot->backlog); + slot->backlog += qdisc_pkt_len(skb); sfq_inc(q, x); if (slot->qlen == 1) { /* The flow is new */ if (q->tail == NULL) { /* It is the first flow */ @@ -552,6 +639,7 @@ static int sfq_change(struct Qdisc *sch, struct nlattr *opt) struct tc_sfq_qopt *ctl = nla_data(opt); struct tc_sfq_qopt_v1 *ctl_v1 = NULL; unsigned int qlen; + struct red_parms *p = NULL; if (opt->nla_len < nla_attr_size(sizeof(*ctl))) return -EINVAL; @@ -560,7 +648,11 @@ static int sfq_change(struct Qdisc *sch, struct nlattr *opt) if (ctl->divisor && (!is_power_of_2(ctl->divisor) || ctl->divisor > 65536)) return -EINVAL; - + if (ctl_v1 && ctl_v1->qth_min) { + p = kmalloc(sizeof(*p), GFP_KERNEL); + if (!p) + return -ENOMEM; + } sch_tree_lock(sch); if (ctl->quantum) { q->quantum = ctl->quantum; @@ -576,6 +668,16 @@ static int sfq_change(struct Qdisc *sch, struct nlattr *opt) if (ctl_v1) { if (ctl_v1->depth) q->maxdepth = min_t(u32, ctl_v1->depth, SFQ_MAX_DEPTH); + if (p) { + swap(q->red_parms, p); + red_set_parms(q->red_parms, + ctl_v1->qth_min, ctl_v1->qth_max, + ctl_v1->Wlog, + ctl_v1->Plog, ctl_v1->Scell_log, + NULL, + ctl_v1->max_P); + } + q->flags = ctl_v1->flags; q->headdrop = ctl_v1->headdrop; } if (ctl->limit) { @@ -594,6 +696,7 @@ static int sfq_change(struct Qdisc *sch, struct nlattr *opt) q->perturbation = net_random(); } sch_tree_unlock(sch); + kfree(p); return 0; } @@ -625,6 +728,7 @@ static void sfq_destroy(struct Qdisc *sch) del_timer_sync(&q->perturb_timer); sfq_free(q->ht); sfq_free(q->slots); + kfree(q->red_parms); } static int sfq_init(struct Qdisc *sch, struct nlattr *opt) @@ -683,6 +787,7 @@ static int sfq_dump(struct Qdisc *sch, struct sk_buff *skb) struct sfq_sched_data *q = qdisc_priv(sch); unsigned char *b = skb_tail_pointer(skb); struct tc_sfq_qopt_v1 opt; + struct red_parms *p = q->red_parms; memset(&opt, 0, sizeof(opt)); opt.v0.quantum = q->quantum; @@ -693,6 +798,17 @@ static int sfq_dump(struct Qdisc *sch, struct sk_buff *skb) opt.depth = q->maxdepth; opt.headdrop = q->headdrop; + if (p) { + opt.qth_min = p->qth_min >> p->Wlog; + opt.qth_max = p->qth_max >> p->Wlog; + opt.Wlog = p->Wlog; + opt.Plog = p->Plog; + opt.Scell_log = p->Scell_log; + opt.max_P = p->max_P; + } + memcpy(&opt.stats, &q->stats, sizeof(opt.stats)); + opt.flags = q->flags; + NLA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt); return skb->len; @@ -747,15 +863,13 @@ static int sfq_dump_class_stats(struct Qdisc *sch, unsigned long cl, sfq_index idx = q->ht[cl - 1]; struct gnet_stats_queue qs = { 0 }; struct tc_sfq_xstats xstats = { 0 }; - struct sk_buff *skb; if (idx != SFQ_EMPTY_SLOT) { const struct sfq_slot *slot = &q->slots[idx]; xstats.allot = slot->allot << SFQ_ALLOT_SHIFT; qs.qlen = slot->qlen; - slot_queue_walk(slot, skb) - qs.backlog += qdisc_pkt_len(skb); + qs.backlog = slot->backlog; } if (gnet_stats_copy_queue(d, &qs) < 0) return -1; -- cgit v1.2.3