1557fc4a0SMichal Kazior /* 2557fc4a0SMichal Kazior * Copyright (c) 2016 Qualcomm Atheros, Inc 3557fc4a0SMichal Kazior * 4557fc4a0SMichal Kazior * GPL v2 5557fc4a0SMichal Kazior * 6557fc4a0SMichal Kazior * Based on net/sched/sch_fq_codel.c 7557fc4a0SMichal Kazior */ 8557fc4a0SMichal Kazior #ifndef __NET_SCHED_FQ_IMPL_H 9557fc4a0SMichal Kazior #define __NET_SCHED_FQ_IMPL_H 10557fc4a0SMichal Kazior 11557fc4a0SMichal Kazior #include <net/fq.h> 12557fc4a0SMichal Kazior 13557fc4a0SMichal Kazior /* functions that are embedded into includer */ 14557fc4a0SMichal Kazior 15557fc4a0SMichal Kazior static struct sk_buff *fq_flow_dequeue(struct fq *fq, 16557fc4a0SMichal Kazior struct fq_flow *flow) 17557fc4a0SMichal Kazior { 18557fc4a0SMichal Kazior struct fq_tin *tin = flow->tin; 19557fc4a0SMichal Kazior struct fq_flow *i; 20557fc4a0SMichal Kazior struct sk_buff *skb; 21557fc4a0SMichal Kazior 22557fc4a0SMichal Kazior lockdep_assert_held(&fq->lock); 23557fc4a0SMichal Kazior 24557fc4a0SMichal Kazior skb = __skb_dequeue(&flow->queue); 25557fc4a0SMichal Kazior if (!skb) 26557fc4a0SMichal Kazior return NULL; 27557fc4a0SMichal Kazior 28557fc4a0SMichal Kazior tin->backlog_bytes -= skb->len; 29557fc4a0SMichal Kazior tin->backlog_packets--; 30557fc4a0SMichal Kazior flow->backlog -= skb->len; 31557fc4a0SMichal Kazior fq->backlog--; 32097b065bSToke Høiland-Jørgensen fq->memory_usage -= skb->truesize; 33557fc4a0SMichal Kazior 34557fc4a0SMichal Kazior if (flow->backlog == 0) { 35557fc4a0SMichal Kazior list_del_init(&flow->backlogchain); 36557fc4a0SMichal Kazior } else { 37557fc4a0SMichal Kazior i = flow; 38557fc4a0SMichal Kazior 39557fc4a0SMichal Kazior list_for_each_entry_continue(i, &fq->backlogs, backlogchain) 40557fc4a0SMichal Kazior if (i->backlog < flow->backlog) 41557fc4a0SMichal Kazior break; 42557fc4a0SMichal Kazior 43557fc4a0SMichal Kazior list_move_tail(&flow->backlogchain, 44557fc4a0SMichal Kazior &i->backlogchain); 45557fc4a0SMichal Kazior } 46557fc4a0SMichal Kazior 47557fc4a0SMichal Kazior return skb; 48557fc4a0SMichal Kazior } 49557fc4a0SMichal Kazior 50557fc4a0SMichal Kazior static struct sk_buff *fq_tin_dequeue(struct fq *fq, 51557fc4a0SMichal Kazior struct fq_tin *tin, 52557fc4a0SMichal Kazior fq_tin_dequeue_t dequeue_func) 53557fc4a0SMichal Kazior { 54557fc4a0SMichal Kazior struct fq_flow *flow; 55557fc4a0SMichal Kazior struct list_head *head; 56557fc4a0SMichal Kazior struct sk_buff *skb; 57557fc4a0SMichal Kazior 58557fc4a0SMichal Kazior lockdep_assert_held(&fq->lock); 59557fc4a0SMichal Kazior 60557fc4a0SMichal Kazior begin: 61557fc4a0SMichal Kazior head = &tin->new_flows; 62557fc4a0SMichal Kazior if (list_empty(head)) { 63557fc4a0SMichal Kazior head = &tin->old_flows; 64557fc4a0SMichal Kazior if (list_empty(head)) 65557fc4a0SMichal Kazior return NULL; 66557fc4a0SMichal Kazior } 67557fc4a0SMichal Kazior 68557fc4a0SMichal Kazior flow = list_first_entry(head, struct fq_flow, flowchain); 69557fc4a0SMichal Kazior 70557fc4a0SMichal Kazior if (flow->deficit <= 0) { 71557fc4a0SMichal Kazior flow->deficit += fq->quantum; 72557fc4a0SMichal Kazior list_move_tail(&flow->flowchain, 73557fc4a0SMichal Kazior &tin->old_flows); 74557fc4a0SMichal Kazior goto begin; 75557fc4a0SMichal Kazior } 76557fc4a0SMichal Kazior 77557fc4a0SMichal Kazior skb = dequeue_func(fq, tin, flow); 78557fc4a0SMichal Kazior if (!skb) { 79557fc4a0SMichal Kazior /* force a pass through old_flows to prevent starvation */ 80557fc4a0SMichal Kazior if ((head == &tin->new_flows) && 81557fc4a0SMichal Kazior !list_empty(&tin->old_flows)) { 82557fc4a0SMichal Kazior list_move_tail(&flow->flowchain, &tin->old_flows); 83557fc4a0SMichal Kazior } else { 84557fc4a0SMichal Kazior list_del_init(&flow->flowchain); 85557fc4a0SMichal Kazior flow->tin = NULL; 86557fc4a0SMichal Kazior } 87557fc4a0SMichal Kazior goto begin; 88557fc4a0SMichal Kazior } 89557fc4a0SMichal Kazior 90557fc4a0SMichal Kazior flow->deficit -= skb->len; 91557fc4a0SMichal Kazior tin->tx_bytes += skb->len; 92557fc4a0SMichal Kazior tin->tx_packets++; 93557fc4a0SMichal Kazior 94557fc4a0SMichal Kazior return skb; 95557fc4a0SMichal Kazior } 96557fc4a0SMichal Kazior 97557fc4a0SMichal Kazior static struct fq_flow *fq_flow_classify(struct fq *fq, 98557fc4a0SMichal Kazior struct fq_tin *tin, 99557fc4a0SMichal Kazior struct sk_buff *skb, 100557fc4a0SMichal Kazior fq_flow_get_default_t get_default_func) 101557fc4a0SMichal Kazior { 102557fc4a0SMichal Kazior struct fq_flow *flow; 103557fc4a0SMichal Kazior u32 hash; 104557fc4a0SMichal Kazior u32 idx; 105557fc4a0SMichal Kazior 106557fc4a0SMichal Kazior lockdep_assert_held(&fq->lock); 107557fc4a0SMichal Kazior 108557fc4a0SMichal Kazior hash = skb_get_hash_perturb(skb, fq->perturbation); 109557fc4a0SMichal Kazior idx = reciprocal_scale(hash, fq->flows_cnt); 110557fc4a0SMichal Kazior flow = &fq->flows[idx]; 111557fc4a0SMichal Kazior 112557fc4a0SMichal Kazior if (flow->tin && flow->tin != tin) { 113557fc4a0SMichal Kazior flow = get_default_func(fq, tin, idx, skb); 114557fc4a0SMichal Kazior tin->collisions++; 115557fc4a0SMichal Kazior fq->collisions++; 116557fc4a0SMichal Kazior } 117557fc4a0SMichal Kazior 118557fc4a0SMichal Kazior if (!flow->tin) 119557fc4a0SMichal Kazior tin->flows++; 120557fc4a0SMichal Kazior 121557fc4a0SMichal Kazior return flow; 122557fc4a0SMichal Kazior } 123557fc4a0SMichal Kazior 124b43e7199SMichal Kazior static void fq_recalc_backlog(struct fq *fq, 125557fc4a0SMichal Kazior struct fq_tin *tin, 126b43e7199SMichal Kazior struct fq_flow *flow) 127557fc4a0SMichal Kazior { 128557fc4a0SMichal Kazior struct fq_flow *i; 129557fc4a0SMichal Kazior 130557fc4a0SMichal Kazior if (list_empty(&flow->backlogchain)) 131557fc4a0SMichal Kazior list_add_tail(&flow->backlogchain, &fq->backlogs); 132557fc4a0SMichal Kazior 133557fc4a0SMichal Kazior i = flow; 134557fc4a0SMichal Kazior list_for_each_entry_continue_reverse(i, &fq->backlogs, 135557fc4a0SMichal Kazior backlogchain) 136557fc4a0SMichal Kazior if (i->backlog > flow->backlog) 137557fc4a0SMichal Kazior break; 138557fc4a0SMichal Kazior 139557fc4a0SMichal Kazior list_move(&flow->backlogchain, &i->backlogchain); 140b43e7199SMichal Kazior } 141b43e7199SMichal Kazior 142b43e7199SMichal Kazior static void fq_tin_enqueue(struct fq *fq, 143b43e7199SMichal Kazior struct fq_tin *tin, 144b43e7199SMichal Kazior struct sk_buff *skb, 145b43e7199SMichal Kazior fq_skb_free_t free_func, 146b43e7199SMichal Kazior fq_flow_get_default_t get_default_func) 147b43e7199SMichal Kazior { 148b43e7199SMichal Kazior struct fq_flow *flow; 149*0bfe649fSToke Høiland-Jørgensen bool oom; 150b43e7199SMichal Kazior 151b43e7199SMichal Kazior lockdep_assert_held(&fq->lock); 152b43e7199SMichal Kazior 153b43e7199SMichal Kazior flow = fq_flow_classify(fq, tin, skb, get_default_func); 154b43e7199SMichal Kazior 155b43e7199SMichal Kazior flow->tin = tin; 156b43e7199SMichal Kazior flow->backlog += skb->len; 157b43e7199SMichal Kazior tin->backlog_bytes += skb->len; 158b43e7199SMichal Kazior tin->backlog_packets++; 159097b065bSToke Høiland-Jørgensen fq->memory_usage += skb->truesize; 160b43e7199SMichal Kazior fq->backlog++; 161b43e7199SMichal Kazior 162b43e7199SMichal Kazior fq_recalc_backlog(fq, tin, flow); 163557fc4a0SMichal Kazior 164557fc4a0SMichal Kazior if (list_empty(&flow->flowchain)) { 165557fc4a0SMichal Kazior flow->deficit = fq->quantum; 166557fc4a0SMichal Kazior list_add_tail(&flow->flowchain, 167557fc4a0SMichal Kazior &tin->new_flows); 168557fc4a0SMichal Kazior } 169557fc4a0SMichal Kazior 170557fc4a0SMichal Kazior __skb_queue_tail(&flow->queue, skb); 171*0bfe649fSToke Høiland-Jørgensen oom = (fq->memory_usage > fq->memory_limit); 172*0bfe649fSToke Høiland-Jørgensen while (fq->backlog > fq->limit || oom) { 173557fc4a0SMichal Kazior flow = list_first_entry_or_null(&fq->backlogs, 174557fc4a0SMichal Kazior struct fq_flow, 175557fc4a0SMichal Kazior backlogchain); 176557fc4a0SMichal Kazior if (!flow) 177557fc4a0SMichal Kazior return; 178557fc4a0SMichal Kazior 179557fc4a0SMichal Kazior skb = fq_flow_dequeue(fq, flow); 180557fc4a0SMichal Kazior if (!skb) 181557fc4a0SMichal Kazior return; 182557fc4a0SMichal Kazior 183557fc4a0SMichal Kazior free_func(fq, flow->tin, flow, skb); 184557fc4a0SMichal Kazior 185557fc4a0SMichal Kazior flow->tin->overlimit++; 186557fc4a0SMichal Kazior fq->overlimit++; 187*0bfe649fSToke Høiland-Jørgensen if (oom) { 188097b065bSToke Høiland-Jørgensen fq->overmemory++; 189*0bfe649fSToke Høiland-Jørgensen oom = (fq->memory_usage > fq->memory_limit); 190*0bfe649fSToke Høiland-Jørgensen } 191557fc4a0SMichal Kazior } 192557fc4a0SMichal Kazior } 193557fc4a0SMichal Kazior 194557fc4a0SMichal Kazior static void fq_flow_reset(struct fq *fq, 195557fc4a0SMichal Kazior struct fq_flow *flow, 196557fc4a0SMichal Kazior fq_skb_free_t free_func) 197557fc4a0SMichal Kazior { 198557fc4a0SMichal Kazior struct sk_buff *skb; 199557fc4a0SMichal Kazior 200557fc4a0SMichal Kazior while ((skb = fq_flow_dequeue(fq, flow))) 201557fc4a0SMichal Kazior free_func(fq, flow->tin, flow, skb); 202557fc4a0SMichal Kazior 203557fc4a0SMichal Kazior if (!list_empty(&flow->flowchain)) 204557fc4a0SMichal Kazior list_del_init(&flow->flowchain); 205557fc4a0SMichal Kazior 206557fc4a0SMichal Kazior if (!list_empty(&flow->backlogchain)) 207557fc4a0SMichal Kazior list_del_init(&flow->backlogchain); 208557fc4a0SMichal Kazior 209557fc4a0SMichal Kazior flow->tin = NULL; 210557fc4a0SMichal Kazior 211557fc4a0SMichal Kazior WARN_ON_ONCE(flow->backlog); 212557fc4a0SMichal Kazior } 213557fc4a0SMichal Kazior 214557fc4a0SMichal Kazior static void fq_tin_reset(struct fq *fq, 215557fc4a0SMichal Kazior struct fq_tin *tin, 216557fc4a0SMichal Kazior fq_skb_free_t free_func) 217557fc4a0SMichal Kazior { 218557fc4a0SMichal Kazior struct list_head *head; 219557fc4a0SMichal Kazior struct fq_flow *flow; 220557fc4a0SMichal Kazior 221557fc4a0SMichal Kazior for (;;) { 222557fc4a0SMichal Kazior head = &tin->new_flows; 223557fc4a0SMichal Kazior if (list_empty(head)) { 224557fc4a0SMichal Kazior head = &tin->old_flows; 225557fc4a0SMichal Kazior if (list_empty(head)) 226557fc4a0SMichal Kazior break; 227557fc4a0SMichal Kazior } 228557fc4a0SMichal Kazior 229557fc4a0SMichal Kazior flow = list_first_entry(head, struct fq_flow, flowchain); 230557fc4a0SMichal Kazior fq_flow_reset(fq, flow, free_func); 231557fc4a0SMichal Kazior } 232557fc4a0SMichal Kazior 233557fc4a0SMichal Kazior WARN_ON_ONCE(tin->backlog_bytes); 234557fc4a0SMichal Kazior WARN_ON_ONCE(tin->backlog_packets); 235557fc4a0SMichal Kazior } 236557fc4a0SMichal Kazior 237557fc4a0SMichal Kazior static void fq_flow_init(struct fq_flow *flow) 238557fc4a0SMichal Kazior { 239557fc4a0SMichal Kazior INIT_LIST_HEAD(&flow->flowchain); 240557fc4a0SMichal Kazior INIT_LIST_HEAD(&flow->backlogchain); 241557fc4a0SMichal Kazior __skb_queue_head_init(&flow->queue); 242557fc4a0SMichal Kazior } 243557fc4a0SMichal Kazior 244557fc4a0SMichal Kazior static void fq_tin_init(struct fq_tin *tin) 245557fc4a0SMichal Kazior { 246557fc4a0SMichal Kazior INIT_LIST_HEAD(&tin->new_flows); 247557fc4a0SMichal Kazior INIT_LIST_HEAD(&tin->old_flows); 248557fc4a0SMichal Kazior } 249557fc4a0SMichal Kazior 250557fc4a0SMichal Kazior static int fq_init(struct fq *fq, int flows_cnt) 251557fc4a0SMichal Kazior { 252557fc4a0SMichal Kazior int i; 253557fc4a0SMichal Kazior 254557fc4a0SMichal Kazior memset(fq, 0, sizeof(fq[0])); 255557fc4a0SMichal Kazior INIT_LIST_HEAD(&fq->backlogs); 256557fc4a0SMichal Kazior spin_lock_init(&fq->lock); 257557fc4a0SMichal Kazior fq->flows_cnt = max_t(u32, flows_cnt, 1); 258557fc4a0SMichal Kazior fq->perturbation = prandom_u32(); 259557fc4a0SMichal Kazior fq->quantum = 300; 260557fc4a0SMichal Kazior fq->limit = 8192; 261097b065bSToke Høiland-Jørgensen fq->memory_limit = 16 << 20; /* 16 MBytes */ 262557fc4a0SMichal Kazior 263557fc4a0SMichal Kazior fq->flows = kcalloc(fq->flows_cnt, sizeof(fq->flows[0]), GFP_KERNEL); 264557fc4a0SMichal Kazior if (!fq->flows) 265557fc4a0SMichal Kazior return -ENOMEM; 266557fc4a0SMichal Kazior 267557fc4a0SMichal Kazior for (i = 0; i < fq->flows_cnt; i++) 268557fc4a0SMichal Kazior fq_flow_init(&fq->flows[i]); 269557fc4a0SMichal Kazior 270557fc4a0SMichal Kazior return 0; 271557fc4a0SMichal Kazior } 272557fc4a0SMichal Kazior 273557fc4a0SMichal Kazior static void fq_reset(struct fq *fq, 274557fc4a0SMichal Kazior fq_skb_free_t free_func) 275557fc4a0SMichal Kazior { 276557fc4a0SMichal Kazior int i; 277557fc4a0SMichal Kazior 278557fc4a0SMichal Kazior for (i = 0; i < fq->flows_cnt; i++) 279557fc4a0SMichal Kazior fq_flow_reset(fq, &fq->flows[i], free_func); 280557fc4a0SMichal Kazior 281557fc4a0SMichal Kazior kfree(fq->flows); 282557fc4a0SMichal Kazior fq->flows = NULL; 283557fc4a0SMichal Kazior } 284557fc4a0SMichal Kazior 285557fc4a0SMichal Kazior #endif 286