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--; 32557fc4a0SMichal Kazior 33557fc4a0SMichal Kazior if (flow->backlog == 0) { 34557fc4a0SMichal Kazior list_del_init(&flow->backlogchain); 35557fc4a0SMichal Kazior } else { 36557fc4a0SMichal Kazior i = flow; 37557fc4a0SMichal Kazior 38557fc4a0SMichal Kazior list_for_each_entry_continue(i, &fq->backlogs, backlogchain) 39557fc4a0SMichal Kazior if (i->backlog < flow->backlog) 40557fc4a0SMichal Kazior break; 41557fc4a0SMichal Kazior 42557fc4a0SMichal Kazior list_move_tail(&flow->backlogchain, 43557fc4a0SMichal Kazior &i->backlogchain); 44557fc4a0SMichal Kazior } 45557fc4a0SMichal Kazior 46557fc4a0SMichal Kazior return skb; 47557fc4a0SMichal Kazior } 48557fc4a0SMichal Kazior 49557fc4a0SMichal Kazior static struct sk_buff *fq_tin_dequeue(struct fq *fq, 50557fc4a0SMichal Kazior struct fq_tin *tin, 51557fc4a0SMichal Kazior fq_tin_dequeue_t dequeue_func) 52557fc4a0SMichal Kazior { 53557fc4a0SMichal Kazior struct fq_flow *flow; 54557fc4a0SMichal Kazior struct list_head *head; 55557fc4a0SMichal Kazior struct sk_buff *skb; 56557fc4a0SMichal Kazior 57557fc4a0SMichal Kazior lockdep_assert_held(&fq->lock); 58557fc4a0SMichal Kazior 59557fc4a0SMichal Kazior begin: 60557fc4a0SMichal Kazior head = &tin->new_flows; 61557fc4a0SMichal Kazior if (list_empty(head)) { 62557fc4a0SMichal Kazior head = &tin->old_flows; 63557fc4a0SMichal Kazior if (list_empty(head)) 64557fc4a0SMichal Kazior return NULL; 65557fc4a0SMichal Kazior } 66557fc4a0SMichal Kazior 67557fc4a0SMichal Kazior flow = list_first_entry(head, struct fq_flow, flowchain); 68557fc4a0SMichal Kazior 69557fc4a0SMichal Kazior if (flow->deficit <= 0) { 70557fc4a0SMichal Kazior flow->deficit += fq->quantum; 71557fc4a0SMichal Kazior list_move_tail(&flow->flowchain, 72557fc4a0SMichal Kazior &tin->old_flows); 73557fc4a0SMichal Kazior goto begin; 74557fc4a0SMichal Kazior } 75557fc4a0SMichal Kazior 76557fc4a0SMichal Kazior skb = dequeue_func(fq, tin, flow); 77557fc4a0SMichal Kazior if (!skb) { 78557fc4a0SMichal Kazior /* force a pass through old_flows to prevent starvation */ 79557fc4a0SMichal Kazior if ((head == &tin->new_flows) && 80557fc4a0SMichal Kazior !list_empty(&tin->old_flows)) { 81557fc4a0SMichal Kazior list_move_tail(&flow->flowchain, &tin->old_flows); 82557fc4a0SMichal Kazior } else { 83557fc4a0SMichal Kazior list_del_init(&flow->flowchain); 84557fc4a0SMichal Kazior flow->tin = NULL; 85557fc4a0SMichal Kazior } 86557fc4a0SMichal Kazior goto begin; 87557fc4a0SMichal Kazior } 88557fc4a0SMichal Kazior 89557fc4a0SMichal Kazior flow->deficit -= skb->len; 90557fc4a0SMichal Kazior tin->tx_bytes += skb->len; 91557fc4a0SMichal Kazior tin->tx_packets++; 92557fc4a0SMichal Kazior 93557fc4a0SMichal Kazior return skb; 94557fc4a0SMichal Kazior } 95557fc4a0SMichal Kazior 96557fc4a0SMichal Kazior static struct fq_flow *fq_flow_classify(struct fq *fq, 97557fc4a0SMichal Kazior struct fq_tin *tin, 98557fc4a0SMichal Kazior struct sk_buff *skb, 99557fc4a0SMichal Kazior fq_flow_get_default_t get_default_func) 100557fc4a0SMichal Kazior { 101557fc4a0SMichal Kazior struct fq_flow *flow; 102557fc4a0SMichal Kazior u32 hash; 103557fc4a0SMichal Kazior u32 idx; 104557fc4a0SMichal Kazior 105557fc4a0SMichal Kazior lockdep_assert_held(&fq->lock); 106557fc4a0SMichal Kazior 107557fc4a0SMichal Kazior hash = skb_get_hash_perturb(skb, fq->perturbation); 108557fc4a0SMichal Kazior idx = reciprocal_scale(hash, fq->flows_cnt); 109557fc4a0SMichal Kazior flow = &fq->flows[idx]; 110557fc4a0SMichal Kazior 111557fc4a0SMichal Kazior if (flow->tin && flow->tin != tin) { 112557fc4a0SMichal Kazior flow = get_default_func(fq, tin, idx, skb); 113557fc4a0SMichal Kazior tin->collisions++; 114557fc4a0SMichal Kazior fq->collisions++; 115557fc4a0SMichal Kazior } 116557fc4a0SMichal Kazior 117557fc4a0SMichal Kazior if (!flow->tin) 118557fc4a0SMichal Kazior tin->flows++; 119557fc4a0SMichal Kazior 120557fc4a0SMichal Kazior return flow; 121557fc4a0SMichal Kazior } 122557fc4a0SMichal Kazior 123*b43e7199SMichal Kazior static void fq_recalc_backlog(struct fq *fq, 124557fc4a0SMichal Kazior struct fq_tin *tin, 125*b43e7199SMichal Kazior struct fq_flow *flow) 126557fc4a0SMichal Kazior { 127557fc4a0SMichal Kazior struct fq_flow *i; 128557fc4a0SMichal Kazior 129557fc4a0SMichal Kazior if (list_empty(&flow->backlogchain)) 130557fc4a0SMichal Kazior list_add_tail(&flow->backlogchain, &fq->backlogs); 131557fc4a0SMichal Kazior 132557fc4a0SMichal Kazior i = flow; 133557fc4a0SMichal Kazior list_for_each_entry_continue_reverse(i, &fq->backlogs, 134557fc4a0SMichal Kazior backlogchain) 135557fc4a0SMichal Kazior if (i->backlog > flow->backlog) 136557fc4a0SMichal Kazior break; 137557fc4a0SMichal Kazior 138557fc4a0SMichal Kazior list_move(&flow->backlogchain, &i->backlogchain); 139*b43e7199SMichal Kazior } 140*b43e7199SMichal Kazior 141*b43e7199SMichal Kazior static void fq_tin_enqueue(struct fq *fq, 142*b43e7199SMichal Kazior struct fq_tin *tin, 143*b43e7199SMichal Kazior struct sk_buff *skb, 144*b43e7199SMichal Kazior fq_skb_free_t free_func, 145*b43e7199SMichal Kazior fq_flow_get_default_t get_default_func) 146*b43e7199SMichal Kazior { 147*b43e7199SMichal Kazior struct fq_flow *flow; 148*b43e7199SMichal Kazior 149*b43e7199SMichal Kazior lockdep_assert_held(&fq->lock); 150*b43e7199SMichal Kazior 151*b43e7199SMichal Kazior flow = fq_flow_classify(fq, tin, skb, get_default_func); 152*b43e7199SMichal Kazior 153*b43e7199SMichal Kazior flow->tin = tin; 154*b43e7199SMichal Kazior flow->backlog += skb->len; 155*b43e7199SMichal Kazior tin->backlog_bytes += skb->len; 156*b43e7199SMichal Kazior tin->backlog_packets++; 157*b43e7199SMichal Kazior fq->backlog++; 158*b43e7199SMichal Kazior 159*b43e7199SMichal Kazior fq_recalc_backlog(fq, tin, flow); 160557fc4a0SMichal Kazior 161557fc4a0SMichal Kazior if (list_empty(&flow->flowchain)) { 162557fc4a0SMichal Kazior flow->deficit = fq->quantum; 163557fc4a0SMichal Kazior list_add_tail(&flow->flowchain, 164557fc4a0SMichal Kazior &tin->new_flows); 165557fc4a0SMichal Kazior } 166557fc4a0SMichal Kazior 167557fc4a0SMichal Kazior __skb_queue_tail(&flow->queue, skb); 168557fc4a0SMichal Kazior 169557fc4a0SMichal Kazior if (fq->backlog > fq->limit) { 170557fc4a0SMichal Kazior flow = list_first_entry_or_null(&fq->backlogs, 171557fc4a0SMichal Kazior struct fq_flow, 172557fc4a0SMichal Kazior backlogchain); 173557fc4a0SMichal Kazior if (!flow) 174557fc4a0SMichal Kazior return; 175557fc4a0SMichal Kazior 176557fc4a0SMichal Kazior skb = fq_flow_dequeue(fq, flow); 177557fc4a0SMichal Kazior if (!skb) 178557fc4a0SMichal Kazior return; 179557fc4a0SMichal Kazior 180557fc4a0SMichal Kazior free_func(fq, flow->tin, flow, skb); 181557fc4a0SMichal Kazior 182557fc4a0SMichal Kazior flow->tin->overlimit++; 183557fc4a0SMichal Kazior fq->overlimit++; 184557fc4a0SMichal Kazior } 185557fc4a0SMichal Kazior } 186557fc4a0SMichal Kazior 187557fc4a0SMichal Kazior static void fq_flow_reset(struct fq *fq, 188557fc4a0SMichal Kazior struct fq_flow *flow, 189557fc4a0SMichal Kazior fq_skb_free_t free_func) 190557fc4a0SMichal Kazior { 191557fc4a0SMichal Kazior struct sk_buff *skb; 192557fc4a0SMichal Kazior 193557fc4a0SMichal Kazior while ((skb = fq_flow_dequeue(fq, flow))) 194557fc4a0SMichal Kazior free_func(fq, flow->tin, flow, skb); 195557fc4a0SMichal Kazior 196557fc4a0SMichal Kazior if (!list_empty(&flow->flowchain)) 197557fc4a0SMichal Kazior list_del_init(&flow->flowchain); 198557fc4a0SMichal Kazior 199557fc4a0SMichal Kazior if (!list_empty(&flow->backlogchain)) 200557fc4a0SMichal Kazior list_del_init(&flow->backlogchain); 201557fc4a0SMichal Kazior 202557fc4a0SMichal Kazior flow->tin = NULL; 203557fc4a0SMichal Kazior 204557fc4a0SMichal Kazior WARN_ON_ONCE(flow->backlog); 205557fc4a0SMichal Kazior } 206557fc4a0SMichal Kazior 207557fc4a0SMichal Kazior static void fq_tin_reset(struct fq *fq, 208557fc4a0SMichal Kazior struct fq_tin *tin, 209557fc4a0SMichal Kazior fq_skb_free_t free_func) 210557fc4a0SMichal Kazior { 211557fc4a0SMichal Kazior struct list_head *head; 212557fc4a0SMichal Kazior struct fq_flow *flow; 213557fc4a0SMichal Kazior 214557fc4a0SMichal Kazior for (;;) { 215557fc4a0SMichal Kazior head = &tin->new_flows; 216557fc4a0SMichal Kazior if (list_empty(head)) { 217557fc4a0SMichal Kazior head = &tin->old_flows; 218557fc4a0SMichal Kazior if (list_empty(head)) 219557fc4a0SMichal Kazior break; 220557fc4a0SMichal Kazior } 221557fc4a0SMichal Kazior 222557fc4a0SMichal Kazior flow = list_first_entry(head, struct fq_flow, flowchain); 223557fc4a0SMichal Kazior fq_flow_reset(fq, flow, free_func); 224557fc4a0SMichal Kazior } 225557fc4a0SMichal Kazior 226557fc4a0SMichal Kazior WARN_ON_ONCE(tin->backlog_bytes); 227557fc4a0SMichal Kazior WARN_ON_ONCE(tin->backlog_packets); 228557fc4a0SMichal Kazior } 229557fc4a0SMichal Kazior 230557fc4a0SMichal Kazior static void fq_flow_init(struct fq_flow *flow) 231557fc4a0SMichal Kazior { 232557fc4a0SMichal Kazior INIT_LIST_HEAD(&flow->flowchain); 233557fc4a0SMichal Kazior INIT_LIST_HEAD(&flow->backlogchain); 234557fc4a0SMichal Kazior __skb_queue_head_init(&flow->queue); 235557fc4a0SMichal Kazior } 236557fc4a0SMichal Kazior 237557fc4a0SMichal Kazior static void fq_tin_init(struct fq_tin *tin) 238557fc4a0SMichal Kazior { 239557fc4a0SMichal Kazior INIT_LIST_HEAD(&tin->new_flows); 240557fc4a0SMichal Kazior INIT_LIST_HEAD(&tin->old_flows); 241557fc4a0SMichal Kazior } 242557fc4a0SMichal Kazior 243557fc4a0SMichal Kazior static int fq_init(struct fq *fq, int flows_cnt) 244557fc4a0SMichal Kazior { 245557fc4a0SMichal Kazior int i; 246557fc4a0SMichal Kazior 247557fc4a0SMichal Kazior memset(fq, 0, sizeof(fq[0])); 248557fc4a0SMichal Kazior INIT_LIST_HEAD(&fq->backlogs); 249557fc4a0SMichal Kazior spin_lock_init(&fq->lock); 250557fc4a0SMichal Kazior fq->flows_cnt = max_t(u32, flows_cnt, 1); 251557fc4a0SMichal Kazior fq->perturbation = prandom_u32(); 252557fc4a0SMichal Kazior fq->quantum = 300; 253557fc4a0SMichal Kazior fq->limit = 8192; 254557fc4a0SMichal Kazior 255557fc4a0SMichal Kazior fq->flows = kcalloc(fq->flows_cnt, sizeof(fq->flows[0]), GFP_KERNEL); 256557fc4a0SMichal Kazior if (!fq->flows) 257557fc4a0SMichal Kazior return -ENOMEM; 258557fc4a0SMichal Kazior 259557fc4a0SMichal Kazior for (i = 0; i < fq->flows_cnt; i++) 260557fc4a0SMichal Kazior fq_flow_init(&fq->flows[i]); 261557fc4a0SMichal Kazior 262557fc4a0SMichal Kazior return 0; 263557fc4a0SMichal Kazior } 264557fc4a0SMichal Kazior 265557fc4a0SMichal Kazior static void fq_reset(struct fq *fq, 266557fc4a0SMichal Kazior fq_skb_free_t free_func) 267557fc4a0SMichal Kazior { 268557fc4a0SMichal Kazior int i; 269557fc4a0SMichal Kazior 270557fc4a0SMichal Kazior for (i = 0; i < fq->flows_cnt; i++) 271557fc4a0SMichal Kazior fq_flow_reset(fq, &fq->flows[i], free_func); 272557fc4a0SMichal Kazior 273557fc4a0SMichal Kazior kfree(fq->flows); 274557fc4a0SMichal Kazior fq->flows = NULL; 275557fc4a0SMichal Kazior } 276557fc4a0SMichal Kazior 277557fc4a0SMichal Kazior #endif 278