LCOV - code coverage report
Current view: top level - net/sched - sch_fifo.c (source / functions) Hit Total Coverage
Test: Real Lines: 0 50 0.0 %
Date: 2020-10-17 15:46:16 Functions: 0 7 0.0 %
Legend: Neither, QEMU, Real, Both Branches: 0 0 -

           Branch data     Line data    Source code
       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                 :          0 : static int bfifo_enqueue(struct sk_buff *skb, struct Qdisc *sch,
      19                 :            :                          struct sk_buff **to_free)
      20                 :            : {
      21                 :          0 :         if (likely(sch->qstats.backlog + qdisc_pkt_len(skb) <= sch->limit))
      22                 :          0 :                 return qdisc_enqueue_tail(skb, sch);
      23                 :            : 
      24                 :          0 :         return qdisc_drop(skb, sch, to_free);
      25                 :            : }
      26                 :            : 
      27                 :          0 : static int pfifo_enqueue(struct sk_buff *skb, struct Qdisc *sch,
      28                 :            :                          struct sk_buff **to_free)
      29                 :            : {
      30                 :          0 :         if (likely(sch->q.qlen < sch->limit))
      31                 :          0 :                 return qdisc_enqueue_tail(skb, sch);
      32                 :            : 
      33                 :          0 :         return qdisc_drop(skb, sch, to_free);
      34                 :            : }
      35                 :            : 
      36                 :          0 : 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                 :          0 :         if (likely(sch->q.qlen < sch->limit))
      42                 :          0 :                 return qdisc_enqueue_tail(skb, sch);
      43                 :            : 
      44                 :          0 :         prev_backlog = sch->qstats.backlog;
      45                 :            :         /* queue full, remove one skb to fulfill the limit */
      46                 :          0 :         __qdisc_queue_drop_head(sch, &sch->q, to_free);
      47                 :            :         qdisc_qstats_drop(sch);
      48                 :            :         qdisc_enqueue_tail(skb, sch);
      49                 :            : 
      50                 :          0 :         qdisc_tree_reduce_backlog(sch, 0, prev_backlog - sch->qstats.backlog);
      51                 :          0 :         return NET_XMIT_CN;
      52                 :            : }
      53                 :            : 
      54                 :          0 : static int fifo_init(struct Qdisc *sch, struct nlattr *opt,
      55                 :            :                      struct netlink_ext_ack *extack)
      56                 :            : {
      57                 :            :         bool bypass;
      58                 :          0 :         bool is_bfifo = sch->ops == &bfifo_qdisc_ops;
      59                 :            : 
      60                 :          0 :         if (opt == NULL) {
      61                 :          0 :                 u32 limit = qdisc_dev(sch)->tx_queue_len;
      62                 :            : 
      63                 :          0 :                 if (is_bfifo)
      64                 :          0 :                         limit *= psched_mtu(qdisc_dev(sch));
      65                 :            : 
      66                 :          0 :                 sch->limit = limit;
      67                 :            :         } else {
      68                 :            :                 struct tc_fifo_qopt *ctl = nla_data(opt);
      69                 :            : 
      70                 :          0 :                 if (nla_len(opt) < sizeof(*ctl))
      71                 :            :                         return -EINVAL;
      72                 :            : 
      73                 :          0 :                 sch->limit = ctl->limit;
      74                 :            :         }
      75                 :            : 
      76                 :          0 :         if (is_bfifo)
      77                 :          0 :                 bypass = sch->limit >= psched_mtu(qdisc_dev(sch));
      78                 :            :         else
      79                 :          0 :                 bypass = sch->limit >= 1;
      80                 :            : 
      81                 :          0 :         if (bypass)
      82                 :          0 :                 sch->flags |= TCQ_F_CAN_BYPASS;
      83                 :            :         else
      84                 :          0 :                 sch->flags &= ~TCQ_F_CAN_BYPASS;
      85                 :            :         return 0;
      86                 :            : }
      87                 :            : 
      88                 :          0 : static int fifo_dump(struct Qdisc *sch, struct sk_buff *skb)
      89                 :            : {
      90                 :          0 :         struct tc_fifo_qopt opt = { .limit = sch->limit };
      91                 :            : 
      92                 :          0 :         if (nla_put(skb, TCA_OPTIONS, sizeof(opt), &opt))
      93                 :            :                 goto nla_put_failure;
      94                 :          0 :         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                 :          0 : 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                 :          0 :         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                 :          0 :         if (nla) {
     153                 :          0 :                 nla->nla_type = RTM_NEWQDISC;
     154                 :          0 :                 nla->nla_len = nla_attr_size(sizeof(struct tc_fifo_qopt));
     155                 :          0 :                 ((struct tc_fifo_qopt *)nla_data(nla))->limit = limit;
     156                 :            : 
     157                 :          0 :                 ret = q->ops->change(q, nla, NULL);
     158                 :          0 :                 kfree(nla);
     159                 :            :         }
     160                 :          0 :         return ret;
     161                 :            : }
     162                 :            : EXPORT_SYMBOL(fifo_set_limit);
     163                 :            : 
     164                 :          0 : 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                 :          0 :         q = qdisc_create_dflt(sch->dev_queue, ops, TC_H_MAKE(sch->handle, 1),
     172                 :            :                               extack);
     173                 :          0 :         if (q) {
     174                 :          0 :                 err = fifo_set_limit(q, limit);
     175                 :          0 :                 if (err < 0) {
     176                 :          0 :                         qdisc_put(q);
     177                 :            :                         q = NULL;
     178                 :            :                 }
     179                 :            :         }
     180                 :            : 
     181                 :          0 :         return q ? : ERR_PTR(err);
     182                 :            : }
     183                 :            : EXPORT_SYMBOL(fifo_create_dflt);
    

Generated by: LCOV version 1.14