Home | History | Annotate | Download | only in sch
      1 /*
      2  * lib/route/sch/fifo.c		(p|b)fifo
      3  *
      4  *	This library is free software; you can redistribute it and/or
      5  *	modify it under the terms of the GNU Lesser General Public
      6  *	License as published by the Free Software Foundation version 2.1
      7  *	of the License.
      8  *
      9  * Copyright (c) 2003-2008 Thomas Graf <tgraf (at) suug.ch>
     10  */
     11 
     12 /**
     13  * @ingroup qdisc_api
     14  * @defgroup fifo Packet/Bytes FIFO (pfifo/bfifo)
     15  * @brief
     16  *
     17  * The FIFO qdisc comes in two flavours:
     18  * @par bfifo (Byte FIFO)
     19  * Allows enqueuing until the currently queued volume in bytes exceeds
     20  * the configured limit.backlog contains currently enqueued volume in bytes.
     21  *
     22  * @par pfifo (Packet FIFO)
     23  * Allows enquueing until the currently queued number of packets
     24  * exceeds the configured limit.
     25  *
     26  * The configuration is exactly the same, the decision which of
     27  * the two variations is going to be used is made based on the
     28  * kind of the qdisc (rtnl_qdisc_set_kind()).
     29  * @{
     30  */
     31 
     32 #include <netlink-local.h>
     33 #include <netlink-tc.h>
     34 #include <netlink/netlink.h>
     35 #include <netlink/route/qdisc.h>
     36 #include <netlink/route/qdisc-modules.h>
     37 #include <netlink/route/sch/fifo.h>
     38 #include <netlink/utils.h>
     39 
     40 /** @cond SKIP */
     41 #define SCH_FIFO_ATTR_LIMIT 1
     42 /** @endcond */
     43 
     44 static inline struct rtnl_fifo *fifo_qdisc(struct rtnl_qdisc *qdisc)
     45 {
     46 	return (struct rtnl_fifo *) qdisc->q_subdata;
     47 }
     48 
     49 static inline struct rtnl_fifo *fifo_alloc(struct rtnl_qdisc *qdisc)
     50 {
     51 	if (!qdisc->q_subdata)
     52 		qdisc->q_subdata = calloc(1, sizeof(struct rtnl_fifo));
     53 
     54 	return fifo_qdisc(qdisc);
     55 }
     56 
     57 static int fifo_msg_parser(struct rtnl_qdisc *qdisc)
     58 {
     59 	struct rtnl_fifo *fifo;
     60 	struct tc_fifo_qopt *opt;
     61 
     62 	if (qdisc->q_opts->d_size < sizeof(struct tc_fifo_qopt))
     63 		return -NLE_INVAL;
     64 
     65 	fifo = fifo_alloc(qdisc);
     66 	if (!fifo)
     67 		return -NLE_NOMEM;
     68 
     69 	opt = (struct tc_fifo_qopt *) qdisc->q_opts->d_data;
     70 	fifo->qf_limit = opt->limit;
     71 	fifo->qf_mask = SCH_FIFO_ATTR_LIMIT;
     72 
     73 	return 0;
     74 }
     75 
     76 static void fifo_free_data(struct rtnl_qdisc *qdisc)
     77 {
     78 	free(qdisc->q_subdata);
     79 }
     80 
     81 static void pfifo_dump_line(struct rtnl_qdisc *qdisc, struct nl_dump_params *p)
     82 {
     83 	struct rtnl_fifo *fifo = fifo_qdisc(qdisc);
     84 
     85 	if (fifo)
     86 		nl_dump(p, " limit %u packets", fifo->qf_limit);
     87 }
     88 
     89 static void bfifo_dump_line(struct rtnl_qdisc *qdisc, struct nl_dump_params *p)
     90 {
     91 	struct rtnl_fifo *fifo = fifo_qdisc(qdisc);
     92 
     93 	if (fifo) {
     94 		char *unit;
     95 		double r;
     96 
     97 		r = nl_cancel_down_bytes(fifo->qf_limit, &unit);
     98 		nl_dump(p, " limit %.1f%s", r, unit);
     99 	}
    100 }
    101 
    102 static struct nl_msg *fifo_get_opts(struct rtnl_qdisc *qdisc)
    103 {
    104 	struct rtnl_fifo *fifo;
    105 	struct tc_fifo_qopt opts;
    106 	struct nl_msg *msg;
    107 
    108 	fifo = fifo_qdisc(qdisc);
    109 	if (!fifo || !(fifo->qf_mask & SCH_FIFO_ATTR_LIMIT))
    110 		return NULL;
    111 
    112 	msg = nlmsg_alloc();
    113 	if (!msg)
    114 		goto errout;
    115 
    116 	memset(&opts, 0, sizeof(opts));
    117 	opts.limit = fifo->qf_limit;
    118 
    119 	if (nlmsg_append(msg, &opts, sizeof(opts), NL_DONTPAD) < 0)
    120 		goto errout;
    121 
    122 	return msg;
    123 errout:
    124 	nlmsg_free(msg);
    125 	return NULL;
    126 }
    127 
    128 /**
    129  * @name Attribute Modification
    130  * @{
    131  */
    132 
    133 /**
    134  * Set limit of FIFO qdisc.
    135  * @arg qdisc		FIFO qdisc to be modified.
    136  * @arg limit		New limit.
    137  * @return 0 on success or a negative error code.
    138  */
    139 int rtnl_qdisc_fifo_set_limit(struct rtnl_qdisc *qdisc, int limit)
    140 {
    141 	struct rtnl_fifo *fifo;
    142 
    143 	fifo = fifo_alloc(qdisc);
    144 	if (!fifo)
    145 		return -NLE_NOMEM;
    146 
    147 	fifo->qf_limit = limit;
    148 	fifo->qf_mask |= SCH_FIFO_ATTR_LIMIT;
    149 
    150 	return 0;
    151 }
    152 
    153 /**
    154  * Get limit of a FIFO qdisc.
    155  * @arg qdisc		FIFO qdisc.
    156  * @return Numeric limit or a negative error code.
    157  */
    158 int rtnl_qdisc_fifo_get_limit(struct rtnl_qdisc *qdisc)
    159 {
    160 	struct rtnl_fifo *fifo;
    161 
    162 	fifo = fifo_qdisc(qdisc);
    163 	if (fifo && fifo->qf_mask & SCH_FIFO_ATTR_LIMIT)
    164 		return fifo->qf_limit;
    165 	else
    166 		return -NLE_NOATTR;
    167 }
    168 
    169 /** @} */
    170 
    171 static struct rtnl_qdisc_ops pfifo_ops = {
    172 	.qo_kind		= "pfifo",
    173 	.qo_msg_parser		= fifo_msg_parser,
    174 	.qo_free_data		= fifo_free_data,
    175 	.qo_dump[NL_DUMP_LINE]	= pfifo_dump_line,
    176 	.qo_get_opts		= fifo_get_opts,
    177 };
    178 
    179 static struct rtnl_qdisc_ops bfifo_ops = {
    180 	.qo_kind		= "bfifo",
    181 	.qo_msg_parser		= fifo_msg_parser,
    182 	.qo_free_data		= fifo_free_data,
    183 	.qo_dump[NL_DUMP_LINE]	= bfifo_dump_line,
    184 	.qo_get_opts		= fifo_get_opts,
    185 };
    186 
    187 static void __init fifo_init(void)
    188 {
    189 	rtnl_qdisc_register(&pfifo_ops);
    190 	rtnl_qdisc_register(&bfifo_ops);
    191 }
    192 
    193 static void __exit fifo_exit(void)
    194 {
    195 	rtnl_qdisc_unregister(&pfifo_ops);
    196 	rtnl_qdisc_unregister(&bfifo_ops);
    197 }
    198 
    199 /** @} */
    200