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