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 15*8c418b5bSJohannes Berg static void fq_adjust_removal(struct fq *fq, 16*8c418b5bSJohannes Berg struct fq_flow *flow, 17*8c418b5bSJohannes Berg struct sk_buff *skb) 18557fc4a0SMichal Kazior { 19557fc4a0SMichal Kazior struct fq_tin *tin = flow->tin; 20557fc4a0SMichal Kazior 21557fc4a0SMichal Kazior tin->backlog_bytes -= skb->len; 22557fc4a0SMichal Kazior tin->backlog_packets--; 23557fc4a0SMichal Kazior flow->backlog -= skb->len; 24557fc4a0SMichal Kazior fq->backlog--; 25097b065bSToke Høiland-Jørgensen fq->memory_usage -= skb->truesize; 26*8c418b5bSJohannes Berg } 27*8c418b5bSJohannes Berg 28*8c418b5bSJohannes Berg static void fq_rejigger_backlog(struct fq *fq, struct fq_flow *flow) 29*8c418b5bSJohannes Berg { 30*8c418b5bSJohannes Berg struct fq_flow *i; 31557fc4a0SMichal Kazior 32557fc4a0SMichal Kazior if (flow->backlog == 0) { 33557fc4a0SMichal Kazior list_del_init(&flow->backlogchain); 34557fc4a0SMichal Kazior } else { 35557fc4a0SMichal Kazior i = flow; 36557fc4a0SMichal Kazior 37557fc4a0SMichal Kazior list_for_each_entry_continue(i, &fq->backlogs, backlogchain) 38557fc4a0SMichal Kazior if (i->backlog < flow->backlog) 39557fc4a0SMichal Kazior break; 40557fc4a0SMichal Kazior 41557fc4a0SMichal Kazior list_move_tail(&flow->backlogchain, 42557fc4a0SMichal Kazior &i->backlogchain); 43557fc4a0SMichal Kazior } 44*8c418b5bSJohannes Berg } 45*8c418b5bSJohannes Berg 46*8c418b5bSJohannes Berg static struct sk_buff *fq_flow_dequeue(struct fq *fq, 47*8c418b5bSJohannes Berg struct fq_flow *flow) 48*8c418b5bSJohannes Berg { 49*8c418b5bSJohannes Berg struct sk_buff *skb; 50*8c418b5bSJohannes Berg 51*8c418b5bSJohannes Berg lockdep_assert_held(&fq->lock); 52*8c418b5bSJohannes Berg 53*8c418b5bSJohannes Berg skb = __skb_dequeue(&flow->queue); 54*8c418b5bSJohannes Berg if (!skb) 55*8c418b5bSJohannes Berg return NULL; 56*8c418b5bSJohannes Berg 57*8c418b5bSJohannes Berg fq_adjust_removal(fq, flow, skb); 58*8c418b5bSJohannes Berg fq_rejigger_backlog(fq, flow); 59557fc4a0SMichal Kazior 60557fc4a0SMichal Kazior return skb; 61557fc4a0SMichal Kazior } 62557fc4a0SMichal Kazior 63557fc4a0SMichal Kazior static struct sk_buff *fq_tin_dequeue(struct fq *fq, 64557fc4a0SMichal Kazior struct fq_tin *tin, 65557fc4a0SMichal Kazior fq_tin_dequeue_t dequeue_func) 66557fc4a0SMichal Kazior { 67557fc4a0SMichal Kazior struct fq_flow *flow; 68557fc4a0SMichal Kazior struct list_head *head; 69557fc4a0SMichal Kazior struct sk_buff *skb; 70557fc4a0SMichal Kazior 71557fc4a0SMichal Kazior lockdep_assert_held(&fq->lock); 72557fc4a0SMichal Kazior 73557fc4a0SMichal Kazior begin: 74557fc4a0SMichal Kazior head = &tin->new_flows; 75557fc4a0SMichal Kazior if (list_empty(head)) { 76557fc4a0SMichal Kazior head = &tin->old_flows; 77557fc4a0SMichal Kazior if (list_empty(head)) 78557fc4a0SMichal Kazior return NULL; 79557fc4a0SMichal Kazior } 80557fc4a0SMichal Kazior 81557fc4a0SMichal Kazior flow = list_first_entry(head, struct fq_flow, flowchain); 82557fc4a0SMichal Kazior 83557fc4a0SMichal Kazior if (flow->deficit <= 0) { 84557fc4a0SMichal Kazior flow->deficit += fq->quantum; 85557fc4a0SMichal Kazior list_move_tail(&flow->flowchain, 86557fc4a0SMichal Kazior &tin->old_flows); 87557fc4a0SMichal Kazior goto begin; 88557fc4a0SMichal Kazior } 89557fc4a0SMichal Kazior 90557fc4a0SMichal Kazior skb = dequeue_func(fq, tin, flow); 91557fc4a0SMichal Kazior if (!skb) { 92557fc4a0SMichal Kazior /* force a pass through old_flows to prevent starvation */ 93557fc4a0SMichal Kazior if ((head == &tin->new_flows) && 94557fc4a0SMichal Kazior !list_empty(&tin->old_flows)) { 95557fc4a0SMichal Kazior list_move_tail(&flow->flowchain, &tin->old_flows); 96557fc4a0SMichal Kazior } else { 97557fc4a0SMichal Kazior list_del_init(&flow->flowchain); 98557fc4a0SMichal Kazior flow->tin = NULL; 99557fc4a0SMichal Kazior } 100557fc4a0SMichal Kazior goto begin; 101557fc4a0SMichal Kazior } 102557fc4a0SMichal Kazior 103557fc4a0SMichal Kazior flow->deficit -= skb->len; 104557fc4a0SMichal Kazior tin->tx_bytes += skb->len; 105557fc4a0SMichal Kazior tin->tx_packets++; 106557fc4a0SMichal Kazior 107557fc4a0SMichal Kazior return skb; 108557fc4a0SMichal Kazior } 109557fc4a0SMichal Kazior 110557fc4a0SMichal Kazior static struct fq_flow *fq_flow_classify(struct fq *fq, 111557fc4a0SMichal Kazior struct fq_tin *tin, 112557fc4a0SMichal Kazior struct sk_buff *skb, 113557fc4a0SMichal Kazior fq_flow_get_default_t get_default_func) 114557fc4a0SMichal Kazior { 115557fc4a0SMichal Kazior struct fq_flow *flow; 116557fc4a0SMichal Kazior u32 hash; 117557fc4a0SMichal Kazior u32 idx; 118557fc4a0SMichal Kazior 119557fc4a0SMichal Kazior lockdep_assert_held(&fq->lock); 120557fc4a0SMichal Kazior 121557fc4a0SMichal Kazior hash = skb_get_hash_perturb(skb, fq->perturbation); 122557fc4a0SMichal Kazior idx = reciprocal_scale(hash, fq->flows_cnt); 123557fc4a0SMichal Kazior flow = &fq->flows[idx]; 124557fc4a0SMichal Kazior 125557fc4a0SMichal Kazior if (flow->tin && flow->tin != tin) { 126557fc4a0SMichal Kazior flow = get_default_func(fq, tin, idx, skb); 127557fc4a0SMichal Kazior tin->collisions++; 128557fc4a0SMichal Kazior fq->collisions++; 129557fc4a0SMichal Kazior } 130557fc4a0SMichal Kazior 131557fc4a0SMichal Kazior if (!flow->tin) 132557fc4a0SMichal Kazior tin->flows++; 133557fc4a0SMichal Kazior 134557fc4a0SMichal Kazior return flow; 135557fc4a0SMichal Kazior } 136557fc4a0SMichal Kazior 137b43e7199SMichal Kazior static void fq_recalc_backlog(struct fq *fq, 138557fc4a0SMichal Kazior struct fq_tin *tin, 139b43e7199SMichal Kazior struct fq_flow *flow) 140557fc4a0SMichal Kazior { 141557fc4a0SMichal Kazior struct fq_flow *i; 142557fc4a0SMichal Kazior 143557fc4a0SMichal Kazior if (list_empty(&flow->backlogchain)) 144557fc4a0SMichal Kazior list_add_tail(&flow->backlogchain, &fq->backlogs); 145557fc4a0SMichal Kazior 146557fc4a0SMichal Kazior i = flow; 147557fc4a0SMichal Kazior list_for_each_entry_continue_reverse(i, &fq->backlogs, 148557fc4a0SMichal Kazior backlogchain) 149557fc4a0SMichal Kazior if (i->backlog > flow->backlog) 150557fc4a0SMichal Kazior break; 151557fc4a0SMichal Kazior 152557fc4a0SMichal Kazior list_move(&flow->backlogchain, &i->backlogchain); 153b43e7199SMichal Kazior } 154b43e7199SMichal Kazior 155b43e7199SMichal Kazior static void fq_tin_enqueue(struct fq *fq, 156b43e7199SMichal Kazior struct fq_tin *tin, 157b43e7199SMichal Kazior struct sk_buff *skb, 158b43e7199SMichal Kazior fq_skb_free_t free_func, 159b43e7199SMichal Kazior fq_flow_get_default_t get_default_func) 160b43e7199SMichal Kazior { 161b43e7199SMichal Kazior struct fq_flow *flow; 162b43e7199SMichal Kazior 163b43e7199SMichal Kazior lockdep_assert_held(&fq->lock); 164b43e7199SMichal Kazior 165b43e7199SMichal Kazior flow = fq_flow_classify(fq, tin, skb, get_default_func); 166b43e7199SMichal Kazior 167b43e7199SMichal Kazior flow->tin = tin; 168b43e7199SMichal Kazior flow->backlog += skb->len; 169b43e7199SMichal Kazior tin->backlog_bytes += skb->len; 170b43e7199SMichal Kazior tin->backlog_packets++; 171097b065bSToke Høiland-Jørgensen fq->memory_usage += skb->truesize; 172b43e7199SMichal Kazior fq->backlog++; 173b43e7199SMichal Kazior 174b43e7199SMichal Kazior fq_recalc_backlog(fq, tin, flow); 175557fc4a0SMichal Kazior 176557fc4a0SMichal Kazior if (list_empty(&flow->flowchain)) { 177557fc4a0SMichal Kazior flow->deficit = fq->quantum; 178557fc4a0SMichal Kazior list_add_tail(&flow->flowchain, 179557fc4a0SMichal Kazior &tin->new_flows); 180557fc4a0SMichal Kazior } 181557fc4a0SMichal Kazior 182557fc4a0SMichal Kazior __skb_queue_tail(&flow->queue, skb); 183557fc4a0SMichal Kazior 184097b065bSToke Høiland-Jørgensen if (fq->backlog > fq->limit || fq->memory_usage > fq->memory_limit) { 185557fc4a0SMichal Kazior flow = list_first_entry_or_null(&fq->backlogs, 186557fc4a0SMichal Kazior struct fq_flow, 187557fc4a0SMichal Kazior backlogchain); 188557fc4a0SMichal Kazior if (!flow) 189557fc4a0SMichal Kazior return; 190557fc4a0SMichal Kazior 191557fc4a0SMichal Kazior skb = fq_flow_dequeue(fq, flow); 192557fc4a0SMichal Kazior if (!skb) 193557fc4a0SMichal Kazior return; 194557fc4a0SMichal Kazior 195557fc4a0SMichal Kazior free_func(fq, flow->tin, flow, skb); 196557fc4a0SMichal Kazior 197557fc4a0SMichal Kazior flow->tin->overlimit++; 198557fc4a0SMichal Kazior fq->overlimit++; 199097b065bSToke Høiland-Jørgensen if (fq->memory_usage > fq->memory_limit) 200097b065bSToke Høiland-Jørgensen fq->overmemory++; 201557fc4a0SMichal Kazior } 202557fc4a0SMichal Kazior } 203557fc4a0SMichal Kazior 204*8c418b5bSJohannes Berg static void fq_flow_filter(struct fq *fq, 205*8c418b5bSJohannes Berg struct fq_flow *flow, 206*8c418b5bSJohannes Berg fq_skb_filter_t filter_func, 207*8c418b5bSJohannes Berg void *filter_data, 208*8c418b5bSJohannes Berg fq_skb_free_t free_func) 209*8c418b5bSJohannes Berg { 210*8c418b5bSJohannes Berg struct fq_tin *tin = flow->tin; 211*8c418b5bSJohannes Berg struct sk_buff *skb, *tmp; 212*8c418b5bSJohannes Berg 213*8c418b5bSJohannes Berg lockdep_assert_held(&fq->lock); 214*8c418b5bSJohannes Berg 215*8c418b5bSJohannes Berg skb_queue_walk_safe(&flow->queue, skb, tmp) { 216*8c418b5bSJohannes Berg if (!filter_func(fq, tin, flow, skb, filter_data)) 217*8c418b5bSJohannes Berg continue; 218*8c418b5bSJohannes Berg 219*8c418b5bSJohannes Berg __skb_unlink(skb, &flow->queue); 220*8c418b5bSJohannes Berg fq_adjust_removal(fq, flow, skb); 221*8c418b5bSJohannes Berg free_func(fq, tin, flow, skb); 222*8c418b5bSJohannes Berg } 223*8c418b5bSJohannes Berg 224*8c418b5bSJohannes Berg fq_rejigger_backlog(fq, flow); 225*8c418b5bSJohannes Berg } 226*8c418b5bSJohannes Berg 227*8c418b5bSJohannes Berg static void fq_tin_filter(struct fq *fq, 228*8c418b5bSJohannes Berg struct fq_tin *tin, 229*8c418b5bSJohannes Berg fq_skb_filter_t filter_func, 230*8c418b5bSJohannes Berg void *filter_data, 231*8c418b5bSJohannes Berg fq_skb_free_t free_func) 232*8c418b5bSJohannes Berg { 233*8c418b5bSJohannes Berg struct fq_flow *flow; 234*8c418b5bSJohannes Berg 235*8c418b5bSJohannes Berg lockdep_assert_held(&fq->lock); 236*8c418b5bSJohannes Berg 237*8c418b5bSJohannes Berg list_for_each_entry(flow, &tin->new_flows, flowchain) 238*8c418b5bSJohannes Berg fq_flow_filter(fq, flow, filter_func, filter_data, free_func); 239*8c418b5bSJohannes Berg list_for_each_entry(flow, &tin->old_flows, flowchain) 240*8c418b5bSJohannes Berg fq_flow_filter(fq, flow, filter_func, filter_data, free_func); 241*8c418b5bSJohannes Berg } 242*8c418b5bSJohannes Berg 243557fc4a0SMichal Kazior static void fq_flow_reset(struct fq *fq, 244557fc4a0SMichal Kazior struct fq_flow *flow, 245557fc4a0SMichal Kazior fq_skb_free_t free_func) 246557fc4a0SMichal Kazior { 247557fc4a0SMichal Kazior struct sk_buff *skb; 248557fc4a0SMichal Kazior 249557fc4a0SMichal Kazior while ((skb = fq_flow_dequeue(fq, flow))) 250557fc4a0SMichal Kazior free_func(fq, flow->tin, flow, skb); 251557fc4a0SMichal Kazior 252557fc4a0SMichal Kazior if (!list_empty(&flow->flowchain)) 253557fc4a0SMichal Kazior list_del_init(&flow->flowchain); 254557fc4a0SMichal Kazior 255557fc4a0SMichal Kazior if (!list_empty(&flow->backlogchain)) 256557fc4a0SMichal Kazior list_del_init(&flow->backlogchain); 257557fc4a0SMichal Kazior 258557fc4a0SMichal Kazior flow->tin = NULL; 259557fc4a0SMichal Kazior 260557fc4a0SMichal Kazior WARN_ON_ONCE(flow->backlog); 261557fc4a0SMichal Kazior } 262557fc4a0SMichal Kazior 263557fc4a0SMichal Kazior static void fq_tin_reset(struct fq *fq, 264557fc4a0SMichal Kazior struct fq_tin *tin, 265557fc4a0SMichal Kazior fq_skb_free_t free_func) 266557fc4a0SMichal Kazior { 267557fc4a0SMichal Kazior struct list_head *head; 268557fc4a0SMichal Kazior struct fq_flow *flow; 269557fc4a0SMichal Kazior 270557fc4a0SMichal Kazior for (;;) { 271557fc4a0SMichal Kazior head = &tin->new_flows; 272557fc4a0SMichal Kazior if (list_empty(head)) { 273557fc4a0SMichal Kazior head = &tin->old_flows; 274557fc4a0SMichal Kazior if (list_empty(head)) 275557fc4a0SMichal Kazior break; 276557fc4a0SMichal Kazior } 277557fc4a0SMichal Kazior 278557fc4a0SMichal Kazior flow = list_first_entry(head, struct fq_flow, flowchain); 279557fc4a0SMichal Kazior fq_flow_reset(fq, flow, free_func); 280557fc4a0SMichal Kazior } 281557fc4a0SMichal Kazior 282557fc4a0SMichal Kazior WARN_ON_ONCE(tin->backlog_bytes); 283557fc4a0SMichal Kazior WARN_ON_ONCE(tin->backlog_packets); 284557fc4a0SMichal Kazior } 285557fc4a0SMichal Kazior 286557fc4a0SMichal Kazior static void fq_flow_init(struct fq_flow *flow) 287557fc4a0SMichal Kazior { 288557fc4a0SMichal Kazior INIT_LIST_HEAD(&flow->flowchain); 289557fc4a0SMichal Kazior INIT_LIST_HEAD(&flow->backlogchain); 290557fc4a0SMichal Kazior __skb_queue_head_init(&flow->queue); 291557fc4a0SMichal Kazior } 292557fc4a0SMichal Kazior 293557fc4a0SMichal Kazior static void fq_tin_init(struct fq_tin *tin) 294557fc4a0SMichal Kazior { 295557fc4a0SMichal Kazior INIT_LIST_HEAD(&tin->new_flows); 296557fc4a0SMichal Kazior INIT_LIST_HEAD(&tin->old_flows); 297557fc4a0SMichal Kazior } 298557fc4a0SMichal Kazior 299557fc4a0SMichal Kazior static int fq_init(struct fq *fq, int flows_cnt) 300557fc4a0SMichal Kazior { 301557fc4a0SMichal Kazior int i; 302557fc4a0SMichal Kazior 303557fc4a0SMichal Kazior memset(fq, 0, sizeof(fq[0])); 304557fc4a0SMichal Kazior INIT_LIST_HEAD(&fq->backlogs); 305557fc4a0SMichal Kazior spin_lock_init(&fq->lock); 306557fc4a0SMichal Kazior fq->flows_cnt = max_t(u32, flows_cnt, 1); 307557fc4a0SMichal Kazior fq->perturbation = prandom_u32(); 308557fc4a0SMichal Kazior fq->quantum = 300; 309557fc4a0SMichal Kazior fq->limit = 8192; 310097b065bSToke Høiland-Jørgensen fq->memory_limit = 16 << 20; /* 16 MBytes */ 311557fc4a0SMichal Kazior 312557fc4a0SMichal Kazior fq->flows = kcalloc(fq->flows_cnt, sizeof(fq->flows[0]), GFP_KERNEL); 313557fc4a0SMichal Kazior if (!fq->flows) 314557fc4a0SMichal Kazior return -ENOMEM; 315557fc4a0SMichal Kazior 316557fc4a0SMichal Kazior for (i = 0; i < fq->flows_cnt; i++) 317557fc4a0SMichal Kazior fq_flow_init(&fq->flows[i]); 318557fc4a0SMichal Kazior 319557fc4a0SMichal Kazior return 0; 320557fc4a0SMichal Kazior } 321557fc4a0SMichal Kazior 322557fc4a0SMichal Kazior static void fq_reset(struct fq *fq, 323557fc4a0SMichal Kazior fq_skb_free_t free_func) 324557fc4a0SMichal Kazior { 325557fc4a0SMichal Kazior int i; 326557fc4a0SMichal Kazior 327557fc4a0SMichal Kazior for (i = 0; i < fq->flows_cnt; i++) 328557fc4a0SMichal Kazior fq_flow_reset(fq, &fq->flows[i], free_func); 329557fc4a0SMichal Kazior 330557fc4a0SMichal Kazior kfree(fq->flows); 331557fc4a0SMichal Kazior fq->flows = NULL; 332557fc4a0SMichal Kazior } 333557fc4a0SMichal Kazior 334557fc4a0SMichal Kazior #endif 335