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--; 32*097b065bSToke 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; 149b43e7199SMichal Kazior 150b43e7199SMichal Kazior lockdep_assert_held(&fq->lock); 151b43e7199SMichal Kazior 152b43e7199SMichal Kazior flow = fq_flow_classify(fq, tin, skb, get_default_func); 153b43e7199SMichal Kazior 154b43e7199SMichal Kazior flow->tin = tin; 155b43e7199SMichal Kazior flow->backlog += skb->len; 156b43e7199SMichal Kazior tin->backlog_bytes += skb->len; 157b43e7199SMichal Kazior tin->backlog_packets++; 158*097b065bSToke Høiland-Jørgensen fq->memory_usage += skb->truesize; 159b43e7199SMichal Kazior fq->backlog++; 160b43e7199SMichal Kazior 161b43e7199SMichal Kazior fq_recalc_backlog(fq, tin, flow); 162557fc4a0SMichal Kazior 163557fc4a0SMichal Kazior if (list_empty(&flow->flowchain)) { 164557fc4a0SMichal Kazior flow->deficit = fq->quantum; 165557fc4a0SMichal Kazior list_add_tail(&flow->flowchain, 166557fc4a0SMichal Kazior &tin->new_flows); 167557fc4a0SMichal Kazior } 168557fc4a0SMichal Kazior 169557fc4a0SMichal Kazior __skb_queue_tail(&flow->queue, skb); 170557fc4a0SMichal Kazior 171*097b065bSToke Høiland-Jørgensen if (fq->backlog > fq->limit || fq->memory_usage > fq->memory_limit) { 172557fc4a0SMichal Kazior flow = list_first_entry_or_null(&fq->backlogs, 173557fc4a0SMichal Kazior struct fq_flow, 174557fc4a0SMichal Kazior backlogchain); 175557fc4a0SMichal Kazior if (!flow) 176557fc4a0SMichal Kazior return; 177557fc4a0SMichal Kazior 178557fc4a0SMichal Kazior skb = fq_flow_dequeue(fq, flow); 179557fc4a0SMichal Kazior if (!skb) 180557fc4a0SMichal Kazior return; 181557fc4a0SMichal Kazior 182557fc4a0SMichal Kazior free_func(fq, flow->tin, flow, skb); 183557fc4a0SMichal Kazior 184557fc4a0SMichal Kazior flow->tin->overlimit++; 185557fc4a0SMichal Kazior fq->overlimit++; 186*097b065bSToke Høiland-Jørgensen if (fq->memory_usage > fq->memory_limit) 187*097b065bSToke Høiland-Jørgensen fq->overmemory++; 188557fc4a0SMichal Kazior } 189557fc4a0SMichal Kazior } 190557fc4a0SMichal Kazior 191557fc4a0SMichal Kazior static void fq_flow_reset(struct fq *fq, 192557fc4a0SMichal Kazior struct fq_flow *flow, 193557fc4a0SMichal Kazior fq_skb_free_t free_func) 194557fc4a0SMichal Kazior { 195557fc4a0SMichal Kazior struct sk_buff *skb; 196557fc4a0SMichal Kazior 197557fc4a0SMichal Kazior while ((skb = fq_flow_dequeue(fq, flow))) 198557fc4a0SMichal Kazior free_func(fq, flow->tin, flow, skb); 199557fc4a0SMichal Kazior 200557fc4a0SMichal Kazior if (!list_empty(&flow->flowchain)) 201557fc4a0SMichal Kazior list_del_init(&flow->flowchain); 202557fc4a0SMichal Kazior 203557fc4a0SMichal Kazior if (!list_empty(&flow->backlogchain)) 204557fc4a0SMichal Kazior list_del_init(&flow->backlogchain); 205557fc4a0SMichal Kazior 206557fc4a0SMichal Kazior flow->tin = NULL; 207557fc4a0SMichal Kazior 208557fc4a0SMichal Kazior WARN_ON_ONCE(flow->backlog); 209557fc4a0SMichal Kazior } 210557fc4a0SMichal Kazior 211557fc4a0SMichal Kazior static void fq_tin_reset(struct fq *fq, 212557fc4a0SMichal Kazior struct fq_tin *tin, 213557fc4a0SMichal Kazior fq_skb_free_t free_func) 214557fc4a0SMichal Kazior { 215557fc4a0SMichal Kazior struct list_head *head; 216557fc4a0SMichal Kazior struct fq_flow *flow; 217557fc4a0SMichal Kazior 218557fc4a0SMichal Kazior for (;;) { 219557fc4a0SMichal Kazior head = &tin->new_flows; 220557fc4a0SMichal Kazior if (list_empty(head)) { 221557fc4a0SMichal Kazior head = &tin->old_flows; 222557fc4a0SMichal Kazior if (list_empty(head)) 223557fc4a0SMichal Kazior break; 224557fc4a0SMichal Kazior } 225557fc4a0SMichal Kazior 226557fc4a0SMichal Kazior flow = list_first_entry(head, struct fq_flow, flowchain); 227557fc4a0SMichal Kazior fq_flow_reset(fq, flow, free_func); 228557fc4a0SMichal Kazior } 229557fc4a0SMichal Kazior 230557fc4a0SMichal Kazior WARN_ON_ONCE(tin->backlog_bytes); 231557fc4a0SMichal Kazior WARN_ON_ONCE(tin->backlog_packets); 232557fc4a0SMichal Kazior } 233557fc4a0SMichal Kazior 234557fc4a0SMichal Kazior static void fq_flow_init(struct fq_flow *flow) 235557fc4a0SMichal Kazior { 236557fc4a0SMichal Kazior INIT_LIST_HEAD(&flow->flowchain); 237557fc4a0SMichal Kazior INIT_LIST_HEAD(&flow->backlogchain); 238557fc4a0SMichal Kazior __skb_queue_head_init(&flow->queue); 239557fc4a0SMichal Kazior } 240557fc4a0SMichal Kazior 241557fc4a0SMichal Kazior static void fq_tin_init(struct fq_tin *tin) 242557fc4a0SMichal Kazior { 243557fc4a0SMichal Kazior INIT_LIST_HEAD(&tin->new_flows); 244557fc4a0SMichal Kazior INIT_LIST_HEAD(&tin->old_flows); 245557fc4a0SMichal Kazior } 246557fc4a0SMichal Kazior 247557fc4a0SMichal Kazior static int fq_init(struct fq *fq, int flows_cnt) 248557fc4a0SMichal Kazior { 249557fc4a0SMichal Kazior int i; 250557fc4a0SMichal Kazior 251557fc4a0SMichal Kazior memset(fq, 0, sizeof(fq[0])); 252557fc4a0SMichal Kazior INIT_LIST_HEAD(&fq->backlogs); 253557fc4a0SMichal Kazior spin_lock_init(&fq->lock); 254557fc4a0SMichal Kazior fq->flows_cnt = max_t(u32, flows_cnt, 1); 255557fc4a0SMichal Kazior fq->perturbation = prandom_u32(); 256557fc4a0SMichal Kazior fq->quantum = 300; 257557fc4a0SMichal Kazior fq->limit = 8192; 258*097b065bSToke Høiland-Jørgensen fq->memory_limit = 16 << 20; /* 16 MBytes */ 259557fc4a0SMichal Kazior 260557fc4a0SMichal Kazior fq->flows = kcalloc(fq->flows_cnt, sizeof(fq->flows[0]), GFP_KERNEL); 261557fc4a0SMichal Kazior if (!fq->flows) 262557fc4a0SMichal Kazior return -ENOMEM; 263557fc4a0SMichal Kazior 264557fc4a0SMichal Kazior for (i = 0; i < fq->flows_cnt; i++) 265557fc4a0SMichal Kazior fq_flow_init(&fq->flows[i]); 266557fc4a0SMichal Kazior 267557fc4a0SMichal Kazior return 0; 268557fc4a0SMichal Kazior } 269557fc4a0SMichal Kazior 270557fc4a0SMichal Kazior static void fq_reset(struct fq *fq, 271557fc4a0SMichal Kazior fq_skb_free_t free_func) 272557fc4a0SMichal Kazior { 273557fc4a0SMichal Kazior int i; 274557fc4a0SMichal Kazior 275557fc4a0SMichal Kazior for (i = 0; i < fq->flows_cnt; i++) 276557fc4a0SMichal Kazior fq_flow_reset(fq, &fq->flows[i], free_func); 277557fc4a0SMichal Kazior 278557fc4a0SMichal Kazior kfree(fq->flows); 279557fc4a0SMichal Kazior fq->flows = NULL; 280557fc4a0SMichal Kazior } 281557fc4a0SMichal Kazior 282557fc4a0SMichal Kazior #endif 283