root/net/sched/sch_fifo.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. bfifo_enqueue
  2. pfifo_enqueue
  3. pfifo_tail_enqueue
  4. fifo_init
  5. fifo_dump
  6. fifo_set_limit
  7. fifo_create_dflt

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * net/sched/sch_fifo.c The simplest FIFO queue.
   4  *
   5  * Authors:     Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
   6  */
   7 
   8 #include <linux/module.h>
   9 #include <linux/slab.h>
  10 #include <linux/types.h>
  11 #include <linux/kernel.h>
  12 #include <linux/errno.h>
  13 #include <linux/skbuff.h>
  14 #include <net/pkt_sched.h>
  15 
  16 /* 1 band FIFO pseudo-"scheduler" */
  17 
  18 static int bfifo_enqueue(struct sk_buff *skb, struct Qdisc *sch,
  19                          struct sk_buff **to_free)
  20 {
  21         if (likely(sch->qstats.backlog + qdisc_pkt_len(skb) <= sch->limit))
  22                 return qdisc_enqueue_tail(skb, sch);
  23 
  24         return qdisc_drop(skb, sch, to_free);
  25 }
  26 
  27 static int pfifo_enqueue(struct sk_buff *skb, struct Qdisc *sch,
  28                          struct sk_buff **to_free)
  29 {
  30         if (likely(sch->q.qlen < sch->limit))
  31                 return qdisc_enqueue_tail(skb, sch);
  32 
  33         return qdisc_drop(skb, sch, to_free);
  34 }
  35 
  36 static int pfifo_tail_enqueue(struct sk_buff *skb, struct Qdisc *sch,
  37                               struct sk_buff **to_free)
  38 {
  39         unsigned int prev_backlog;
  40 
  41         if (likely(sch->q.qlen < sch->limit))
  42                 return qdisc_enqueue_tail(skb, sch);
  43 
  44         prev_backlog = sch->qstats.backlog;
  45         /* queue full, remove one skb to fulfill the limit */
  46         __qdisc_queue_drop_head(sch, &sch->q, to_free);
  47         qdisc_qstats_drop(sch);
  48         qdisc_enqueue_tail(skb, sch);
  49 
  50         qdisc_tree_reduce_backlog(sch, 0, prev_backlog - sch->qstats.backlog);
  51         return NET_XMIT_CN;
  52 }
  53 
  54 static int fifo_init(struct Qdisc *sch, struct nlattr *opt,
  55                      struct netlink_ext_ack *extack)
  56 {
  57         bool bypass;
  58         bool is_bfifo = sch->ops == &bfifo_qdisc_ops;
  59 
  60         if (opt == NULL) {
  61                 u32 limit = qdisc_dev(sch)->tx_queue_len;
  62 
  63                 if (is_bfifo)
  64                         limit *= psched_mtu(qdisc_dev(sch));
  65 
  66                 sch->limit = limit;
  67         } else {
  68                 struct tc_fifo_qopt *ctl = nla_data(opt);
  69 
  70                 if (nla_len(opt) < sizeof(*ctl))
  71                         return -EINVAL;
  72 
  73                 sch->limit = ctl->limit;
  74         }
  75 
  76         if (is_bfifo)
  77                 bypass = sch->limit >= psched_mtu(qdisc_dev(sch));
  78         else
  79                 bypass = sch->limit >= 1;
  80 
  81         if (bypass)
  82                 sch->flags |= TCQ_F_CAN_BYPASS;
  83         else
  84                 sch->flags &= ~TCQ_F_CAN_BYPASS;
  85         return 0;
  86 }
  87 
  88 static int fifo_dump(struct Qdisc *sch, struct sk_buff *skb)
  89 {
  90         struct tc_fifo_qopt opt = { .limit = sch->limit };
  91 
  92         if (nla_put(skb, TCA_OPTIONS, sizeof(opt), &opt))
  93                 goto nla_put_failure;
  94         return skb->len;
  95 
  96 nla_put_failure:
  97         return -1;
  98 }
  99 
 100 struct Qdisc_ops pfifo_qdisc_ops __read_mostly = {
 101         .id             =       "pfifo",
 102         .priv_size      =       0,
 103         .enqueue        =       pfifo_enqueue,
 104         .dequeue        =       qdisc_dequeue_head,
 105         .peek           =       qdisc_peek_head,
 106         .init           =       fifo_init,
 107         .reset          =       qdisc_reset_queue,
 108         .change         =       fifo_init,
 109         .dump           =       fifo_dump,
 110         .owner          =       THIS_MODULE,
 111 };
 112 EXPORT_SYMBOL(pfifo_qdisc_ops);
 113 
 114 struct Qdisc_ops bfifo_qdisc_ops __read_mostly = {
 115         .id             =       "bfifo",
 116         .priv_size      =       0,
 117         .enqueue        =       bfifo_enqueue,
 118         .dequeue        =       qdisc_dequeue_head,
 119         .peek           =       qdisc_peek_head,
 120         .init           =       fifo_init,
 121         .reset          =       qdisc_reset_queue,
 122         .change         =       fifo_init,
 123         .dump           =       fifo_dump,
 124         .owner          =       THIS_MODULE,
 125 };
 126 EXPORT_SYMBOL(bfifo_qdisc_ops);
 127 
 128 struct Qdisc_ops pfifo_head_drop_qdisc_ops __read_mostly = {
 129         .id             =       "pfifo_head_drop",
 130         .priv_size      =       0,
 131         .enqueue        =       pfifo_tail_enqueue,
 132         .dequeue        =       qdisc_dequeue_head,
 133         .peek           =       qdisc_peek_head,
 134         .init           =       fifo_init,
 135         .reset          =       qdisc_reset_queue,
 136         .change         =       fifo_init,
 137         .dump           =       fifo_dump,
 138         .owner          =       THIS_MODULE,
 139 };
 140 
 141 /* Pass size change message down to embedded FIFO */
 142 int fifo_set_limit(struct Qdisc *q, unsigned int limit)
 143 {
 144         struct nlattr *nla;
 145         int ret = -ENOMEM;
 146 
 147         /* Hack to avoid sending change message to non-FIFO */
 148         if (strncmp(q->ops->id + 1, "fifo", 4) != 0)
 149                 return 0;
 150 
 151         nla = kmalloc(nla_attr_size(sizeof(struct tc_fifo_qopt)), GFP_KERNEL);
 152         if (nla) {
 153                 nla->nla_type = RTM_NEWQDISC;
 154                 nla->nla_len = nla_attr_size(sizeof(struct tc_fifo_qopt));
 155                 ((struct tc_fifo_qopt *)nla_data(nla))->limit = limit;
 156 
 157                 ret = q->ops->change(q, nla, NULL);
 158                 kfree(nla);
 159         }
 160         return ret;
 161 }
 162 EXPORT_SYMBOL(fifo_set_limit);
 163 
 164 struct Qdisc *fifo_create_dflt(struct Qdisc *sch, struct Qdisc_ops *ops,
 165                                unsigned int limit,
 166                                struct netlink_ext_ack *extack)
 167 {
 168         struct Qdisc *q;
 169         int err = -ENOMEM;
 170 
 171         q = qdisc_create_dflt(sch->dev_queue, ops, TC_H_MAKE(sch->handle, 1),
 172                               extack);
 173         if (q) {
 174                 err = fifo_set_limit(q, limit);
 175                 if (err < 0) {
 176                         qdisc_put(q);
 177                         q = NULL;
 178                 }
 179         }
 180 
 181         return q ? : ERR_PTR(err);
 182 }
 183 EXPORT_SYMBOL(fifo_create_dflt);

/* [<][>][^][v][top][bottom][index][help] */