From 9ecd04bc04af7df98b3a93c571e31b6ef6a90681 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 8 Nov 2011 10:45:04 +0000 Subject: sch_choke: use skb_header_pointer() Remove the assumption that skb_get_rxhash() makes IP header and ports linear, and use skb_header_pointer() instead in choke_match_flow() This permits __skb_get_rxhash() to use skb_header_pointer() eventually. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/sched/sch_choke.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) (limited to 'net/sched/sch_choke.c') diff --git a/net/sched/sch_choke.c b/net/sched/sch_choke.c index 3422b25df9e..061bcb744bb 100644 --- a/net/sched/sch_choke.c +++ b/net/sched/sch_choke.c @@ -152,15 +152,14 @@ static bool choke_match_flow(struct sk_buff *skb1, { int off1, off2, poff; const u32 *ports1, *ports2; + u32 _ports1, _ports2; u8 ip_proto; __u32 hash1; if (skb1->protocol != skb2->protocol) return false; - /* Use hash value as quick check - * Assumes that __skb_get_rxhash makes IP header and ports linear - */ + /* Use rxhash value as quick check */ hash1 = skb_get_rxhash(skb1); if (!hash1 || hash1 != skb_get_rxhash(skb2)) return false; @@ -172,10 +171,12 @@ static bool choke_match_flow(struct sk_buff *skb1, switch (skb1->protocol) { case __constant_htons(ETH_P_IP): { const struct iphdr *ip1, *ip2; + struct iphdr _ip1, _ip2; - ip1 = (const struct iphdr *) (skb1->data + off1); - ip2 = (const struct iphdr *) (skb2->data + off2); - + ip1 = skb_header_pointer(skb1, off1, sizeof(_ip1), &_ip1); + ip2 = skb_header_pointer(skb2, off2, sizeof(_ip2), &_ip2); + if (!ip1 || !ip2) + return false; ip_proto = ip1->protocol; if (ip_proto != ip2->protocol || ip1->saddr != ip2->saddr || ip1->daddr != ip2->daddr) @@ -190,9 +191,12 @@ static bool choke_match_flow(struct sk_buff *skb1, case __constant_htons(ETH_P_IPV6): { const struct ipv6hdr *ip1, *ip2; + struct ipv6hdr _ip1, _ip2; - ip1 = (const struct ipv6hdr *) (skb1->data + off1); - ip2 = (const struct ipv6hdr *) (skb2->data + off2); + ip1 = skb_header_pointer(skb1, off1, sizeof(_ip1), &_ip1); + ip2 = skb_header_pointer(skb2, off2, sizeof(_ip2), &_ip2); + if (!ip1 || !ip2) + return false; ip_proto = ip1->nexthdr; if (ip_proto != ip2->nexthdr || @@ -214,8 +218,11 @@ static bool choke_match_flow(struct sk_buff *skb1, off1 += poff; off2 += poff; - ports1 = (__force u32 *)(skb1->data + off1); - ports2 = (__force u32 *)(skb2->data + off2); + ports1 = skb_header_pointer(skb1, off1, sizeof(_ports1), &_ports1); + ports2 = skb_header_pointer(skb2, off2, sizeof(_ports2), &_ports2); + if (!ports1 || !ports2) + return false; + return *ports1 == *ports2; } -- cgit v1.2.3-70-g09d2 From 2bcc34bb987e07abcf6bc30b7f92fbf22b59d4ef Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 29 Nov 2011 04:22:15 +0000 Subject: sch_choke: use skb_flow_dissect() Instead of using a custom flow dissector, use skb_flow_dissect() and benefit from tunnelling support. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/sched/sch_choke.c | 120 +++++++++++++------------------------------------- 1 file changed, 31 insertions(+), 89 deletions(-) (limited to 'net/sched/sch_choke.c') diff --git a/net/sched/sch_choke.c b/net/sched/sch_choke.c index 061bcb744bb..205d369a217 100644 --- a/net/sched/sch_choke.c +++ b/net/sched/sch_choke.c @@ -19,10 +19,7 @@ #include #include #include -#include -#include -#include -#include +#include /* CHOKe stateless AQM for fair bandwidth allocation @@ -142,92 +139,10 @@ static void choke_drop_by_idx(struct Qdisc *sch, unsigned int idx) --sch->q.qlen; } -/* - * Compare flow of two packets - * Returns true only if source and destination address and port match. - * false for special cases - */ -static bool choke_match_flow(struct sk_buff *skb1, - struct sk_buff *skb2) -{ - int off1, off2, poff; - const u32 *ports1, *ports2; - u32 _ports1, _ports2; - u8 ip_proto; - __u32 hash1; - - if (skb1->protocol != skb2->protocol) - return false; - - /* Use rxhash value as quick check */ - hash1 = skb_get_rxhash(skb1); - if (!hash1 || hash1 != skb_get_rxhash(skb2)) - return false; - - /* Probably match, but be sure to avoid hash collisions */ - off1 = skb_network_offset(skb1); - off2 = skb_network_offset(skb2); - - switch (skb1->protocol) { - case __constant_htons(ETH_P_IP): { - const struct iphdr *ip1, *ip2; - struct iphdr _ip1, _ip2; - - ip1 = skb_header_pointer(skb1, off1, sizeof(_ip1), &_ip1); - ip2 = skb_header_pointer(skb2, off2, sizeof(_ip2), &_ip2); - if (!ip1 || !ip2) - return false; - ip_proto = ip1->protocol; - if (ip_proto != ip2->protocol || - ip1->saddr != ip2->saddr || ip1->daddr != ip2->daddr) - return false; - - if (ip_is_fragment(ip1) | ip_is_fragment(ip2)) - ip_proto = 0; - off1 += ip1->ihl * 4; - off2 += ip2->ihl * 4; - break; - } - - case __constant_htons(ETH_P_IPV6): { - const struct ipv6hdr *ip1, *ip2; - struct ipv6hdr _ip1, _ip2; - - ip1 = skb_header_pointer(skb1, off1, sizeof(_ip1), &_ip1); - ip2 = skb_header_pointer(skb2, off2, sizeof(_ip2), &_ip2); - if (!ip1 || !ip2) - return false; - - ip_proto = ip1->nexthdr; - if (ip_proto != ip2->nexthdr || - ipv6_addr_cmp(&ip1->saddr, &ip2->saddr) || - ipv6_addr_cmp(&ip1->daddr, &ip2->daddr)) - return false; - off1 += 40; - off2 += 40; - } - - default: /* Maybe compare MAC header here? */ - return false; - } - - poff = proto_ports_offset(ip_proto); - if (poff < 0) - return true; - - off1 += poff; - off2 += poff; - - ports1 = skb_header_pointer(skb1, off1, sizeof(_ports1), &_ports1); - ports2 = skb_header_pointer(skb2, off2, sizeof(_ports2), &_ports2); - if (!ports1 || !ports2) - return false; - - return *ports1 == *ports2; -} - struct choke_skb_cb { - u16 classid; + u16 classid; + u8 keys_valid; + struct flow_keys keys; }; static inline struct choke_skb_cb *choke_skb_cb(const struct sk_buff *skb) @@ -247,6 +162,32 @@ static u16 choke_get_classid(const struct sk_buff *skb) return choke_skb_cb(skb)->classid; } +/* + * Compare flow of two packets + * Returns true only if source and destination address and port match. + * false for special cases + */ +static bool choke_match_flow(struct sk_buff *skb1, + struct sk_buff *skb2) +{ + if (skb1->protocol != skb2->protocol) + return false; + + if (!choke_skb_cb(skb1)->keys_valid) { + choke_skb_cb(skb1)->keys_valid = 1; + skb_flow_dissect(skb1, &choke_skb_cb(skb1)->keys); + } + + if (!choke_skb_cb(skb2)->keys_valid) { + choke_skb_cb(skb2)->keys_valid = 1; + skb_flow_dissect(skb2, &choke_skb_cb(skb2)->keys); + } + + return !memcmp(&choke_skb_cb(skb1)->keys, + &choke_skb_cb(skb2)->keys, + sizeof(struct flow_keys)); +} + /* * Classify flow using either: * 1. pre-existing classification result in skb @@ -333,6 +274,7 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch) goto other_drop; /* Packet was eaten by filter */ } + choke_skb_cb(skb)->keys_valid = 0; /* Compute average queue usage (see RED) */ p->qavg = red_calc_qavg(p, sch->q.qlen); if (red_is_idling(p)) -- cgit v1.2.3-70-g09d2 From a73ed26bbae7327370c5bd298f07de78df9e3466 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 9 Dec 2011 02:46:45 +0000 Subject: sch_red: generalize accurate MAX_P support to RED/GRED/CHOKE Now RED uses a Q0.32 number to store max_p (max probability), allow RED/GRED/CHOKE to use/report full resolution at config/dump time. Old tc binaries are non aware of new attributes, and still set/get Plog. New tc binary set/get both Plog and max_p for backward compatibility, they display "probability value" if they get max_p from new kernels. # tc -d qdisc show dev ... ... qdisc red 10: parent 1:1 limit 360Kb min 30Kb max 90Kb ecn ewma 5 probability 0.09 Scell_log 15 Make sure we avoid potential divides by 0 in reciprocal_value(), if (max_th - min_th) is big. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/linux/pkt_sched.h | 2 ++ include/net/red.h | 16 +++++++++++----- net/sched/sch_choke.c | 8 +++++++- net/sched/sch_gred.c | 22 ++++++++++++++++++---- net/sched/sch_red.c | 9 +++++++-- 5 files changed, 45 insertions(+), 12 deletions(-) (limited to 'net/sched/sch_choke.c') diff --git a/include/linux/pkt_sched.h b/include/linux/pkt_sched.h index e41e0d4de24..8786ea741f5 100644 --- a/include/linux/pkt_sched.h +++ b/include/linux/pkt_sched.h @@ -216,6 +216,7 @@ enum { TCA_GRED_PARMS, TCA_GRED_STAB, TCA_GRED_DPS, + TCA_GRED_MAX_P, __TCA_GRED_MAX, }; @@ -255,6 +256,7 @@ enum { TCA_CHOKE_UNSPEC, TCA_CHOKE_PARMS, TCA_CHOKE_STAB, + TCA_CHOKE_MAX_P, __TCA_CHOKE_MAX, }; diff --git a/include/net/red.h b/include/net/red.h index 24606b22d01..ef715a16cce 100644 --- a/include/net/red.h +++ b/include/net/red.h @@ -155,9 +155,10 @@ static inline u32 red_maxp(u8 Plog) static inline void red_set_parms(struct red_parms *p, u32 qth_min, u32 qth_max, u8 Wlog, u8 Plog, - u8 Scell_log, u8 *stab) + u8 Scell_log, u8 *stab, u32 max_P) { int delta = qth_max - qth_min; + u32 max_p_delta; /* Reset average queue length, the value is strictly bound * to the parameters below, reseting hurts a bit but leaving @@ -173,10 +174,14 @@ static inline void red_set_parms(struct red_parms *p, if (delta < 0) delta = 1; p->qth_delta = delta; - p->max_P = red_maxp(Plog); - p->max_P *= delta; /* max_P = (qth_max-qth_min)/2^Plog */ - - p->max_P_reciprocal = reciprocal_value(p->max_P / delta); + if (!max_P) { + max_P = red_maxp(Plog); + max_P *= delta; /* max_P = (qth_max - qth_min)/2^Plog */ + } + p->max_P = max_P; + max_p_delta = max_P / delta; + max_p_delta = max(max_p_delta, 1U); + p->max_P_reciprocal = reciprocal_value(max_p_delta); /* RED Adaptative target : * [min_th + 0.4*(min_th - max_th), @@ -380,6 +385,7 @@ static inline void red_adaptative_algo(struct red_parms *p) p->max_P = (p->max_P/10)*9; /* maxp = maxp * Beta */ max_p_delta = DIV_ROUND_CLOSEST(p->max_P, p->qth_delta); + max_p_delta = max(max_p_delta, 1U); p->max_P_reciprocal = reciprocal_value(max_p_delta); } #endif diff --git a/net/sched/sch_choke.c b/net/sched/sch_choke.c index 205d369a217..bef00acb8bd 100644 --- a/net/sched/sch_choke.c +++ b/net/sched/sch_choke.c @@ -394,6 +394,7 @@ static void choke_reset(struct Qdisc *sch) static const struct nla_policy choke_policy[TCA_CHOKE_MAX + 1] = { [TCA_CHOKE_PARMS] = { .len = sizeof(struct tc_red_qopt) }, [TCA_CHOKE_STAB] = { .len = RED_STAB_SIZE }, + [TCA_CHOKE_MAX_P] = { .type = NLA_U32 }, }; @@ -415,6 +416,7 @@ static int choke_change(struct Qdisc *sch, struct nlattr *opt) int err; struct sk_buff **old = NULL; unsigned int mask; + u32 max_P; if (opt == NULL) return -EINVAL; @@ -427,6 +429,8 @@ static int choke_change(struct Qdisc *sch, struct nlattr *opt) tb[TCA_CHOKE_STAB] == NULL) return -EINVAL; + max_P = tb[TCA_CHOKE_MAX_P] ? nla_get_u32(tb[TCA_CHOKE_MAX_P]) : 0; + ctl = nla_data(tb[TCA_CHOKE_PARMS]); if (ctl->limit > CHOKE_MAX_QUEUE) @@ -476,7 +480,8 @@ static int choke_change(struct Qdisc *sch, struct nlattr *opt) red_set_parms(&q->parms, ctl->qth_min, ctl->qth_max, ctl->Wlog, ctl->Plog, ctl->Scell_log, - nla_data(tb[TCA_CHOKE_STAB])); + nla_data(tb[TCA_CHOKE_STAB]), + max_P); if (q->head == q->tail) red_end_of_idle_period(&q->parms); @@ -510,6 +515,7 @@ static int choke_dump(struct Qdisc *sch, struct sk_buff *skb) goto nla_put_failure; NLA_PUT(skb, TCA_CHOKE_PARMS, sizeof(opt), &opt); + NLA_PUT_U32(skb, TCA_CHOKE_MAX_P, q->parms.max_P); return nla_nest_end(skb, opts); nla_put_failure: diff --git a/net/sched/sch_gred.c b/net/sched/sch_gred.c index b9493a09a87..a1b7407ac2a 100644 --- a/net/sched/sch_gred.c +++ b/net/sched/sch_gred.c @@ -34,7 +34,7 @@ struct gred_sched; struct gred_sched_data { u32 limit; /* HARD maximal queue length */ - u32 DP; /* the drop pramaters */ + u32 DP; /* the drop parameters */ u32 bytesin; /* bytes seen on virtualQ so far*/ u32 packetsin; /* packets seen on virtualQ so far*/ u32 backlog; /* bytes on the virtualQ */ @@ -379,7 +379,8 @@ static inline int gred_change_table_def(struct Qdisc *sch, struct nlattr *dps) } static inline int gred_change_vq(struct Qdisc *sch, int dp, - struct tc_gred_qopt *ctl, int prio, u8 *stab) + struct tc_gred_qopt *ctl, int prio, + u8 *stab, u32 max_P) { struct gred_sched *table = qdisc_priv(sch); struct gred_sched_data *q; @@ -400,7 +401,7 @@ static inline int gred_change_vq(struct Qdisc *sch, int dp, red_set_parms(&q->parms, ctl->qth_min, ctl->qth_max, ctl->Wlog, ctl->Plog, - ctl->Scell_log, stab); + ctl->Scell_log, stab, max_P); return 0; } @@ -409,6 +410,7 @@ static const struct nla_policy gred_policy[TCA_GRED_MAX + 1] = { [TCA_GRED_PARMS] = { .len = sizeof(struct tc_gred_qopt) }, [TCA_GRED_STAB] = { .len = 256 }, [TCA_GRED_DPS] = { .len = sizeof(struct tc_gred_sopt) }, + [TCA_GRED_MAX_P] = { .type = NLA_U32 }, }; static int gred_change(struct Qdisc *sch, struct nlattr *opt) @@ -418,6 +420,7 @@ static int gred_change(struct Qdisc *sch, struct nlattr *opt) struct nlattr *tb[TCA_GRED_MAX + 1]; int err, prio = GRED_DEF_PRIO; u8 *stab; + u32 max_P; if (opt == NULL) return -EINVAL; @@ -433,6 +436,8 @@ static int gred_change(struct Qdisc *sch, struct nlattr *opt) tb[TCA_GRED_STAB] == NULL) return -EINVAL; + max_P = tb[TCA_GRED_MAX_P] ? nla_get_u32(tb[TCA_GRED_MAX_P]) : 0; + err = -EINVAL; ctl = nla_data(tb[TCA_GRED_PARMS]); stab = nla_data(tb[TCA_GRED_STAB]); @@ -457,7 +462,7 @@ static int gred_change(struct Qdisc *sch, struct nlattr *opt) sch_tree_lock(sch); - err = gred_change_vq(sch, ctl->DP, ctl, prio, stab); + err = gred_change_vq(sch, ctl->DP, ctl, prio, stab, max_P); if (err < 0) goto errout_locked; @@ -498,6 +503,7 @@ static int gred_dump(struct Qdisc *sch, struct sk_buff *skb) struct gred_sched *table = qdisc_priv(sch); struct nlattr *parms, *opts = NULL; int i; + u32 max_p[MAX_DPs]; struct tc_gred_sopt sopt = { .DPs = table->DPs, .def_DP = table->def, @@ -509,6 +515,14 @@ static int gred_dump(struct Qdisc *sch, struct sk_buff *skb) if (opts == NULL) goto nla_put_failure; NLA_PUT(skb, TCA_GRED_DPS, sizeof(sopt), &sopt); + + for (i = 0; i < MAX_DPs; i++) { + struct gred_sched_data *q = table->tab[i]; + + max_p[i] = q ? q->parms.max_P : 0; + } + NLA_PUT(skb, TCA_GRED_MAX_P, sizeof(max_p), max_p); + parms = nla_nest_start(skb, TCA_GRED_PARMS); if (parms == NULL) goto nla_put_failure; diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c index 8f5a85bf9d1..ce2256a17d7 100644 --- a/net/sched/sch_red.c +++ b/net/sched/sch_red.c @@ -170,6 +170,7 @@ static void red_destroy(struct Qdisc *sch) static const struct nla_policy red_policy[TCA_RED_MAX + 1] = { [TCA_RED_PARMS] = { .len = sizeof(struct tc_red_qopt) }, [TCA_RED_STAB] = { .len = RED_STAB_SIZE }, + [TCA_RED_MAX_P] = { .type = NLA_U32 }, }; static int red_change(struct Qdisc *sch, struct nlattr *opt) @@ -179,6 +180,7 @@ static int red_change(struct Qdisc *sch, struct nlattr *opt) struct tc_red_qopt *ctl; struct Qdisc *child = NULL; int err; + u32 max_P; if (opt == NULL) return -EINVAL; @@ -191,6 +193,8 @@ static int red_change(struct Qdisc *sch, struct nlattr *opt) tb[TCA_RED_STAB] == NULL) return -EINVAL; + max_P = tb[TCA_RED_MAX_P] ? nla_get_u32(tb[TCA_RED_MAX_P]) : 0; + ctl = nla_data(tb[TCA_RED_PARMS]); if (ctl->limit > 0) { @@ -209,8 +213,9 @@ static int red_change(struct Qdisc *sch, struct nlattr *opt) } red_set_parms(&q->parms, ctl->qth_min, ctl->qth_max, ctl->Wlog, - ctl->Plog, ctl->Scell_log, - nla_data(tb[TCA_RED_STAB])); + ctl->Plog, ctl->Scell_log, + nla_data(tb[TCA_RED_STAB]), + max_P); del_timer(&q->adapt_timer); if (ctl->flags & TC_RED_ADAPTATIVE) -- cgit v1.2.3-70-g09d2 From eeca6688d6599c28bc449a45facb67d7f203be74 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 5 Jan 2012 02:25:16 +0000 Subject: net_sched: red: split red_parms into parms and vars This patch splits the red_parms structure into two components. One holding the RED 'constant' parameters, and one containing the variables. This permits a size reduction of GRED qdisc, and is a preliminary step to add an optional RED unit to SFQ. SFQRED will have a single red_parms structure shared by all flows, and a private red_vars per flow. Signed-off-by: Eric Dumazet CC: Dave Taht CC: Stephen Hemminger Signed-off-by: David S. Miller --- include/net/red.h | 98 +++++++++++++++++++++++++++++---------------------- net/sched/sch_choke.c | 40 +++++++++++---------- net/sched/sch_gred.c | 45 ++++++++++++----------- net/sched/sch_red.c | 29 ++++++++------- 4 files changed, 117 insertions(+), 95 deletions(-) (limited to 'net/sched/sch_choke.c') diff --git a/include/net/red.h b/include/net/red.h index ef715a16cce..baab385a473 100644 --- a/include/net/red.h +++ b/include/net/red.h @@ -137,7 +137,9 @@ struct red_parms { u8 Wlog; /* log(W) */ u8 Plog; /* random number bits */ u8 Stab[RED_STAB_SIZE]; +}; +struct red_vars { /* Variables */ int qcount; /* Number of packets since last random number generation */ @@ -152,6 +154,16 @@ static inline u32 red_maxp(u8 Plog) return Plog < 32 ? (~0U >> Plog) : ~0U; } +static inline void red_set_vars(struct red_vars *v) +{ + /* Reset average queue length, the value is strictly bound + * to the parameters below, reseting hurts a bit but leaving + * it might result in an unreasonable qavg for a while. --TGR + */ + v->qavg = 0; + + v->qcount = -1; +} static inline void red_set_parms(struct red_parms *p, u32 qth_min, u32 qth_max, u8 Wlog, u8 Plog, @@ -160,13 +172,6 @@ static inline void red_set_parms(struct red_parms *p, int delta = qth_max - qth_min; u32 max_p_delta; - /* Reset average queue length, the value is strictly bound - * to the parameters below, reseting hurts a bit but leaving - * it might result in an unreasonable qavg for a while. --TGR - */ - p->qavg = 0; - - p->qcount = -1; p->qth_min = qth_min << Wlog; p->qth_max = qth_max << Wlog; p->Wlog = Wlog; @@ -197,31 +202,32 @@ static inline void red_set_parms(struct red_parms *p, memcpy(p->Stab, stab, sizeof(p->Stab)); } -static inline int red_is_idling(const struct red_parms *p) +static inline int red_is_idling(const struct red_vars *v) { - return p->qidlestart.tv64 != 0; + return v->qidlestart.tv64 != 0; } -static inline void red_start_of_idle_period(struct red_parms *p) +static inline void red_start_of_idle_period(struct red_vars *v) { - p->qidlestart = ktime_get(); + v->qidlestart = ktime_get(); } -static inline void red_end_of_idle_period(struct red_parms *p) +static inline void red_end_of_idle_period(struct red_vars *v) { - p->qidlestart.tv64 = 0; + v->qidlestart.tv64 = 0; } -static inline void red_restart(struct red_parms *p) +static inline void red_restart(struct red_vars *v) { - red_end_of_idle_period(p); - p->qavg = 0; - p->qcount = -1; + red_end_of_idle_period(v); + v->qavg = 0; + v->qcount = -1; } -static inline unsigned long red_calc_qavg_from_idle_time(const struct red_parms *p) +static inline unsigned long red_calc_qavg_from_idle_time(const struct red_parms *p, + const struct red_vars *v) { - s64 delta = ktime_us_delta(ktime_get(), p->qidlestart); + s64 delta = ktime_us_delta(ktime_get(), v->qidlestart); long us_idle = min_t(s64, delta, p->Scell_max); int shift; @@ -248,7 +254,7 @@ static inline unsigned long red_calc_qavg_from_idle_time(const struct red_parms shift = p->Stab[(us_idle >> p->Scell_log) & RED_STAB_MASK]; if (shift) - return p->qavg >> shift; + return v->qavg >> shift; else { /* Approximate initial part of exponent with linear function: * @@ -257,16 +263,17 @@ static inline unsigned long red_calc_qavg_from_idle_time(const struct red_parms * Seems, it is the best solution to * problem of too coarse exponent tabulation. */ - us_idle = (p->qavg * (u64)us_idle) >> p->Scell_log; + us_idle = (v->qavg * (u64)us_idle) >> p->Scell_log; - if (us_idle < (p->qavg >> 1)) - return p->qavg - us_idle; + if (us_idle < (v->qavg >> 1)) + return v->qavg - us_idle; else - return p->qavg >> 1; + return v->qavg >> 1; } } static inline unsigned long red_calc_qavg_no_idle_time(const struct red_parms *p, + const struct red_vars *v, unsigned int backlog) { /* @@ -278,16 +285,17 @@ static inline unsigned long red_calc_qavg_no_idle_time(const struct red_parms *p * * --ANK (980924) */ - return p->qavg + (backlog - (p->qavg >> p->Wlog)); + return v->qavg + (backlog - (v->qavg >> p->Wlog)); } static inline unsigned long red_calc_qavg(const struct red_parms *p, + const struct red_vars *v, unsigned int backlog) { - if (!red_is_idling(p)) - return red_calc_qavg_no_idle_time(p, backlog); + if (!red_is_idling(v)) + return red_calc_qavg_no_idle_time(p, v, backlog); else - return red_calc_qavg_from_idle_time(p); + return red_calc_qavg_from_idle_time(p, v); } @@ -296,7 +304,9 @@ static inline u32 red_random(const struct red_parms *p) return reciprocal_divide(net_random(), p->max_P_reciprocal); } -static inline int red_mark_probability(const struct red_parms *p, unsigned long qavg) +static inline int red_mark_probability(const struct red_parms *p, + const struct red_vars *v, + unsigned long qavg) { /* The formula used below causes questions. @@ -314,7 +324,7 @@ static inline int red_mark_probability(const struct red_parms *p, unsigned long Any questions? --ANK (980924) */ - return !(((qavg - p->qth_min) >> p->Wlog) * p->qcount < p->qR); + return !(((qavg - p->qth_min) >> p->Wlog) * v->qcount < v->qR); } enum { @@ -323,7 +333,7 @@ enum { RED_ABOVE_MAX_TRESH, }; -static inline int red_cmp_thresh(struct red_parms *p, unsigned long qavg) +static inline int red_cmp_thresh(const struct red_parms *p, unsigned long qavg) { if (qavg < p->qth_min) return RED_BELOW_MIN_THRESH; @@ -339,27 +349,29 @@ enum { RED_HARD_MARK, }; -static inline int red_action(struct red_parms *p, unsigned long qavg) +static inline int red_action(const struct red_parms *p, + struct red_vars *v, + unsigned long qavg) { switch (red_cmp_thresh(p, qavg)) { case RED_BELOW_MIN_THRESH: - p->qcount = -1; + v->qcount = -1; return RED_DONT_MARK; case RED_BETWEEN_TRESH: - if (++p->qcount) { - if (red_mark_probability(p, qavg)) { - p->qcount = 0; - p->qR = red_random(p); + if (++v->qcount) { + if (red_mark_probability(p, v, qavg)) { + v->qcount = 0; + v->qR = red_random(p); return RED_PROB_MARK; } } else - p->qR = red_random(p); + v->qR = red_random(p); return RED_DONT_MARK; case RED_ABOVE_MAX_TRESH: - p->qcount = -1; + v->qcount = -1; return RED_HARD_MARK; } @@ -367,14 +379,14 @@ static inline int red_action(struct red_parms *p, unsigned long qavg) return RED_DONT_MARK; } -static inline void red_adaptative_algo(struct red_parms *p) +static inline void red_adaptative_algo(struct red_parms *p, struct red_vars *v) { unsigned long qavg; u32 max_p_delta; - qavg = p->qavg; - if (red_is_idling(p)) - qavg = red_calc_qavg_from_idle_time(p); + qavg = v->qavg; + if (red_is_idling(v)) + qavg = red_calc_qavg_from_idle_time(p, v); /* p->qavg is fixed point number with point at Wlog */ qavg >>= p->Wlog; diff --git a/net/sched/sch_choke.c b/net/sched/sch_choke.c index bef00acb8bd..e465064d39a 100644 --- a/net/sched/sch_choke.c +++ b/net/sched/sch_choke.c @@ -57,6 +57,7 @@ struct choke_sched_data { struct red_parms parms; /* Variables */ + struct red_vars vars; struct tcf_proto *filter_list; struct { u32 prob_drop; /* Early probability drops */ @@ -265,7 +266,7 @@ static bool choke_match_random(const struct choke_sched_data *q, static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch) { struct choke_sched_data *q = qdisc_priv(sch); - struct red_parms *p = &q->parms; + const struct red_parms *p = &q->parms; int ret = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS; if (q->filter_list) { @@ -276,13 +277,13 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch) choke_skb_cb(skb)->keys_valid = 0; /* Compute average queue usage (see RED) */ - p->qavg = red_calc_qavg(p, sch->q.qlen); - if (red_is_idling(p)) - red_end_of_idle_period(p); + q->vars.qavg = red_calc_qavg(p, &q->vars, sch->q.qlen); + if (red_is_idling(&q->vars)) + red_end_of_idle_period(&q->vars); /* Is queue small? */ - if (p->qavg <= p->qth_min) - p->qcount = -1; + if (q->vars.qavg <= p->qth_min) + q->vars.qcount = -1; else { unsigned int idx; @@ -294,8 +295,8 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch) } /* Queue is large, always mark/drop */ - if (p->qavg > p->qth_max) { - p->qcount = -1; + if (q->vars.qavg > p->qth_max) { + q->vars.qcount = -1; sch->qstats.overlimits++; if (use_harddrop(q) || !use_ecn(q) || @@ -305,10 +306,10 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch) } q->stats.forced_mark++; - } else if (++p->qcount) { - if (red_mark_probability(p, p->qavg)) { - p->qcount = 0; - p->qR = red_random(p); + } else if (++q->vars.qcount) { + if (red_mark_probability(p, &q->vars, q->vars.qavg)) { + q->vars.qcount = 0; + q->vars.qR = red_random(p); sch->qstats.overlimits++; if (!use_ecn(q) || !INET_ECN_set_ce(skb)) { @@ -319,7 +320,7 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch) q->stats.prob_mark++; } } else - p->qR = red_random(p); + q->vars.qR = red_random(p); } /* Admit new packet */ @@ -353,8 +354,8 @@ static struct sk_buff *choke_dequeue(struct Qdisc *sch) struct sk_buff *skb; if (q->head == q->tail) { - if (!red_is_idling(&q->parms)) - red_start_of_idle_period(&q->parms); + if (!red_is_idling(&q->vars)) + red_start_of_idle_period(&q->vars); return NULL; } @@ -377,8 +378,8 @@ static unsigned int choke_drop(struct Qdisc *sch) if (len > 0) q->stats.other++; else { - if (!red_is_idling(&q->parms)) - red_start_of_idle_period(&q->parms); + if (!red_is_idling(&q->vars)) + red_start_of_idle_period(&q->vars); } return len; @@ -388,7 +389,7 @@ static void choke_reset(struct Qdisc *sch) { struct choke_sched_data *q = qdisc_priv(sch); - red_restart(&q->parms); + red_restart(&q->vars); } static const struct nla_policy choke_policy[TCA_CHOKE_MAX + 1] = { @@ -482,9 +483,10 @@ static int choke_change(struct Qdisc *sch, struct nlattr *opt) ctl->Plog, ctl->Scell_log, nla_data(tb[TCA_CHOKE_STAB]), max_P); + red_set_vars(&q->vars); if (q->head == q->tail) - red_end_of_idle_period(&q->parms); + red_end_of_idle_period(&q->vars); sch_tree_unlock(sch); choke_free(old); diff --git a/net/sched/sch_gred.c b/net/sched/sch_gred.c index 53204de71c3..0b15236be7b 100644 --- a/net/sched/sch_gred.c +++ b/net/sched/sch_gred.c @@ -41,6 +41,7 @@ struct gred_sched_data { u8 prio; /* the prio of this vq */ struct red_parms parms; + struct red_vars vars; struct red_stats stats; }; @@ -55,7 +56,7 @@ struct gred_sched { u32 red_flags; u32 DPs; u32 def; - struct red_parms wred_set; + struct red_vars wred_set; }; static inline int gred_wred_mode(struct gred_sched *table) @@ -125,17 +126,17 @@ static inline u16 tc_index_to_dp(struct sk_buff *skb) return skb->tc_index & GRED_VQ_MASK; } -static inline void gred_load_wred_set(struct gred_sched *table, +static inline void gred_load_wred_set(const struct gred_sched *table, struct gred_sched_data *q) { - q->parms.qavg = table->wred_set.qavg; - q->parms.qidlestart = table->wred_set.qidlestart; + q->vars.qavg = table->wred_set.qavg; + q->vars.qidlestart = table->wred_set.qidlestart; } static inline void gred_store_wred_set(struct gred_sched *table, struct gred_sched_data *q) { - table->wred_set.qavg = q->parms.qavg; + table->wred_set.qavg = q->vars.qavg; } static inline int gred_use_ecn(struct gred_sched *t) @@ -170,7 +171,7 @@ static int gred_enqueue(struct sk_buff *skb, struct Qdisc *sch) goto drop; } - /* fix tc_index? --could be controvesial but needed for + /* fix tc_index? --could be controversial but needed for requeueing */ skb->tc_index = (skb->tc_index & ~GRED_VQ_MASK) | dp; } @@ -181,8 +182,8 @@ static int gred_enqueue(struct sk_buff *skb, struct Qdisc *sch) for (i = 0; i < t->DPs; i++) { if (t->tab[i] && t->tab[i]->prio < q->prio && - !red_is_idling(&t->tab[i]->parms)) - qavg += t->tab[i]->parms.qavg; + !red_is_idling(&t->tab[i]->vars)) + qavg += t->tab[i]->vars.qavg; } } @@ -193,15 +194,17 @@ static int gred_enqueue(struct sk_buff *skb, struct Qdisc *sch) if (gred_wred_mode(t)) gred_load_wred_set(t, q); - q->parms.qavg = red_calc_qavg(&q->parms, gred_backlog(t, q, sch)); + q->vars.qavg = red_calc_qavg(&q->parms, + &q->vars, + gred_backlog(t, q, sch)); - if (red_is_idling(&q->parms)) - red_end_of_idle_period(&q->parms); + if (red_is_idling(&q->vars)) + red_end_of_idle_period(&q->vars); if (gred_wred_mode(t)) gred_store_wred_set(t, q); - switch (red_action(&q->parms, q->parms.qavg + qavg)) { + switch (red_action(&q->parms, &q->vars, q->vars.qavg + qavg)) { case RED_DONT_MARK: break; @@ -260,7 +263,7 @@ static struct sk_buff *gred_dequeue(struct Qdisc *sch) q->backlog -= qdisc_pkt_len(skb); if (!q->backlog && !gred_wred_mode(t)) - red_start_of_idle_period(&q->parms); + red_start_of_idle_period(&q->vars); } return skb; @@ -293,7 +296,7 @@ static unsigned int gred_drop(struct Qdisc *sch) q->stats.other++; if (!q->backlog && !gred_wred_mode(t)) - red_start_of_idle_period(&q->parms); + red_start_of_idle_period(&q->vars); } qdisc_drop(skb, sch); @@ -320,7 +323,7 @@ static void gred_reset(struct Qdisc *sch) if (!q) continue; - red_restart(&q->parms); + red_restart(&q->vars); q->backlog = 0; } } @@ -398,12 +401,12 @@ static inline int gred_change_vq(struct Qdisc *sch, int dp, q->limit = ctl->limit; if (q->backlog == 0) - red_end_of_idle_period(&q->parms); + red_end_of_idle_period(&q->vars); red_set_parms(&q->parms, ctl->qth_min, ctl->qth_max, ctl->Wlog, ctl->Plog, ctl->Scell_log, stab, max_P); - + red_set_vars(&q->vars); return 0; } @@ -563,12 +566,12 @@ static int gred_dump(struct Qdisc *sch, struct sk_buff *skb) opt.bytesin = q->bytesin; if (gred_wred_mode(table)) { - q->parms.qidlestart = - table->tab[table->def]->parms.qidlestart; - q->parms.qavg = table->tab[table->def]->parms.qavg; + q->vars.qidlestart = + table->tab[table->def]->vars.qidlestart; + q->vars.qavg = table->tab[table->def]->vars.qavg; } - opt.qave = red_calc_qavg(&q->parms, q->parms.qavg); + opt.qave = red_calc_qavg(&q->parms, &q->vars, q->vars.qavg); append_opt: if (nla_append(skb, sizeof(opt), &opt) < 0) diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c index ce2256a17d7..a5cc3012cf4 100644 --- a/net/sched/sch_red.c +++ b/net/sched/sch_red.c @@ -41,6 +41,7 @@ struct red_sched_data { unsigned char flags; struct timer_list adapt_timer; struct red_parms parms; + struct red_vars vars; struct red_stats stats; struct Qdisc *qdisc; }; @@ -61,12 +62,14 @@ static int red_enqueue(struct sk_buff *skb, struct Qdisc *sch) struct Qdisc *child = q->qdisc; int ret; - q->parms.qavg = red_calc_qavg(&q->parms, child->qstats.backlog); + q->vars.qavg = red_calc_qavg(&q->parms, + &q->vars, + child->qstats.backlog); - if (red_is_idling(&q->parms)) - red_end_of_idle_period(&q->parms); + if (red_is_idling(&q->vars)) + red_end_of_idle_period(&q->vars); - switch (red_action(&q->parms, q->parms.qavg)) { + switch (red_action(&q->parms, &q->vars, q->vars.qavg)) { case RED_DONT_MARK: break; @@ -117,8 +120,8 @@ static struct sk_buff *red_dequeue(struct Qdisc *sch) qdisc_bstats_update(sch, skb); sch->q.qlen--; } else { - if (!red_is_idling(&q->parms)) - red_start_of_idle_period(&q->parms); + if (!red_is_idling(&q->vars)) + red_start_of_idle_period(&q->vars); } return skb; } @@ -144,8 +147,8 @@ static unsigned int red_drop(struct Qdisc *sch) return len; } - if (!red_is_idling(&q->parms)) - red_start_of_idle_period(&q->parms); + if (!red_is_idling(&q->vars)) + red_start_of_idle_period(&q->vars); return 0; } @@ -156,7 +159,7 @@ static void red_reset(struct Qdisc *sch) qdisc_reset(q->qdisc); sch->q.qlen = 0; - red_restart(&q->parms); + red_restart(&q->vars); } static void red_destroy(struct Qdisc *sch) @@ -212,17 +215,19 @@ static int red_change(struct Qdisc *sch, struct nlattr *opt) q->qdisc = child; } - red_set_parms(&q->parms, ctl->qth_min, ctl->qth_max, ctl->Wlog, + red_set_parms(&q->parms, + ctl->qth_min, ctl->qth_max, ctl->Wlog, ctl->Plog, ctl->Scell_log, nla_data(tb[TCA_RED_STAB]), max_P); + red_set_vars(&q->vars); del_timer(&q->adapt_timer); if (ctl->flags & TC_RED_ADAPTATIVE) mod_timer(&q->adapt_timer, jiffies + HZ/2); if (!q->qdisc->q.qlen) - red_start_of_idle_period(&q->parms); + red_start_of_idle_period(&q->vars); sch_tree_unlock(sch); return 0; @@ -235,7 +240,7 @@ static inline void red_adaptative_timer(unsigned long arg) spinlock_t *root_lock = qdisc_lock(qdisc_root_sleeping(sch)); spin_lock(root_lock); - red_adaptative_algo(&q->parms); + red_adaptative_algo(&q->parms, &q->vars); mod_timer(&q->adapt_timer, jiffies + HZ/2); spin_unlock(root_lock); } -- cgit v1.2.3-70-g09d2