libnl 2.0
|
00001 /* 00002 * lib/route/sch/fifo.c (p|b)fifo 00003 * 00004 * This library is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU Lesser General Public 00006 * License as published by the Free Software Foundation version 2.1 00007 * of the License. 00008 * 00009 * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> 00010 */ 00011 00012 /** 00013 * @ingroup qdisc_api 00014 * @defgroup fifo Packet/Bytes FIFO (pfifo/bfifo) 00015 * @brief 00016 * 00017 * The FIFO qdisc comes in two flavours: 00018 * @par bfifo (Byte FIFO) 00019 * Allows enqueuing until the currently queued volume in bytes exceeds 00020 * the configured limit.backlog contains currently enqueued volume in bytes. 00021 * 00022 * @par pfifo (Packet FIFO) 00023 * Allows enquueing until the currently queued number of packets 00024 * exceeds the configured limit. 00025 * 00026 * The configuration is exactly the same, the decision which of 00027 * the two variations is going to be used is made based on the 00028 * kind of the qdisc (rtnl_qdisc_set_kind()). 00029 * @{ 00030 */ 00031 00032 #include <netlink-local.h> 00033 #include <netlink-tc.h> 00034 #include <netlink/netlink.h> 00035 #include <netlink/route/qdisc.h> 00036 #include <netlink/route/qdisc-modules.h> 00037 #include <netlink/route/sch/fifo.h> 00038 #include <netlink/utils.h> 00039 00040 /** @cond SKIP */ 00041 #define SCH_FIFO_ATTR_LIMIT 1 00042 /** @endcond */ 00043 00044 static inline struct rtnl_fifo *fifo_qdisc(struct rtnl_qdisc *qdisc) 00045 { 00046 return (struct rtnl_fifo *) qdisc->q_subdata; 00047 } 00048 00049 static inline struct rtnl_fifo *fifo_alloc(struct rtnl_qdisc *qdisc) 00050 { 00051 if (!qdisc->q_subdata) 00052 qdisc->q_subdata = calloc(1, sizeof(struct rtnl_fifo)); 00053 00054 return fifo_qdisc(qdisc); 00055 } 00056 00057 static int fifo_msg_parser(struct rtnl_qdisc *qdisc) 00058 { 00059 struct rtnl_fifo *fifo; 00060 struct tc_fifo_qopt *opt; 00061 00062 if (qdisc->q_opts->d_size < sizeof(struct tc_fifo_qopt)) 00063 return -NLE_INVAL; 00064 00065 fifo = fifo_alloc(qdisc); 00066 if (!fifo) 00067 return -NLE_NOMEM; 00068 00069 opt = (struct tc_fifo_qopt *) qdisc->q_opts->d_data; 00070 fifo->qf_limit = opt->limit; 00071 fifo->qf_mask = SCH_FIFO_ATTR_LIMIT; 00072 00073 return 0; 00074 } 00075 00076 static void fifo_free_data(struct rtnl_qdisc *qdisc) 00077 { 00078 free(qdisc->q_subdata); 00079 } 00080 00081 static void pfifo_dump_line(struct rtnl_qdisc *qdisc, struct nl_dump_params *p) 00082 { 00083 struct rtnl_fifo *fifo = fifo_qdisc(qdisc); 00084 00085 if (fifo) 00086 nl_dump(p, " limit %u packets", fifo->qf_limit); 00087 } 00088 00089 static void bfifo_dump_line(struct rtnl_qdisc *qdisc, struct nl_dump_params *p) 00090 { 00091 struct rtnl_fifo *fifo = fifo_qdisc(qdisc); 00092 00093 if (fifo) { 00094 char *unit; 00095 double r; 00096 00097 r = nl_cancel_down_bytes(fifo->qf_limit, &unit); 00098 nl_dump(p, " limit %.1f%s", r, unit); 00099 } 00100 } 00101 00102 static struct nl_msg *fifo_get_opts(struct rtnl_qdisc *qdisc) 00103 { 00104 struct rtnl_fifo *fifo; 00105 struct tc_fifo_qopt opts; 00106 struct nl_msg *msg; 00107 00108 fifo = fifo_qdisc(qdisc); 00109 if (!fifo || !(fifo->qf_mask & SCH_FIFO_ATTR_LIMIT)) 00110 return NULL; 00111 00112 msg = nlmsg_alloc(); 00113 if (!msg) 00114 goto errout; 00115 00116 memset(&opts, 0, sizeof(opts)); 00117 opts.limit = fifo->qf_limit; 00118 00119 if (nlmsg_append(msg, &opts, sizeof(opts), NL_DONTPAD) < 0) 00120 goto errout; 00121 00122 return msg; 00123 errout: 00124 nlmsg_free(msg); 00125 return NULL; 00126 } 00127 00128 /** 00129 * @name Attribute Modification 00130 * @{ 00131 */ 00132 00133 /** 00134 * Set limit of FIFO qdisc. 00135 * @arg qdisc FIFO qdisc to be modified. 00136 * @arg limit New limit. 00137 * @return 0 on success or a negative error code. 00138 */ 00139 int rtnl_qdisc_fifo_set_limit(struct rtnl_qdisc *qdisc, int limit) 00140 { 00141 struct rtnl_fifo *fifo; 00142 00143 fifo = fifo_alloc(qdisc); 00144 if (!fifo) 00145 return -NLE_NOMEM; 00146 00147 fifo->qf_limit = limit; 00148 fifo->qf_mask |= SCH_FIFO_ATTR_LIMIT; 00149 00150 return 0; 00151 } 00152 00153 /** 00154 * Get limit of a FIFO qdisc. 00155 * @arg qdisc FIFO qdisc. 00156 * @return Numeric limit or a negative error code. 00157 */ 00158 int rtnl_qdisc_fifo_get_limit(struct rtnl_qdisc *qdisc) 00159 { 00160 struct rtnl_fifo *fifo; 00161 00162 fifo = fifo_qdisc(qdisc); 00163 if (fifo && fifo->qf_mask & SCH_FIFO_ATTR_LIMIT) 00164 return fifo->qf_limit; 00165 else 00166 return -NLE_NOATTR; 00167 } 00168 00169 /** @} */ 00170 00171 static struct rtnl_qdisc_ops pfifo_ops = { 00172 .qo_kind = "pfifo", 00173 .qo_msg_parser = fifo_msg_parser, 00174 .qo_free_data = fifo_free_data, 00175 .qo_dump[NL_DUMP_LINE] = pfifo_dump_line, 00176 .qo_get_opts = fifo_get_opts, 00177 }; 00178 00179 static struct rtnl_qdisc_ops bfifo_ops = { 00180 .qo_kind = "bfifo", 00181 .qo_msg_parser = fifo_msg_parser, 00182 .qo_free_data = fifo_free_data, 00183 .qo_dump[NL_DUMP_LINE] = bfifo_dump_line, 00184 .qo_get_opts = fifo_get_opts, 00185 }; 00186 00187 static void __init fifo_init(void) 00188 { 00189 rtnl_qdisc_register(&pfifo_ops); 00190 rtnl_qdisc_register(&bfifo_ops); 00191 } 00192 00193 static void __exit fifo_exit(void) 00194 { 00195 rtnl_qdisc_unregister(&pfifo_ops); 00196 rtnl_qdisc_unregister(&bfifo_ops); 00197 } 00198 00199 /** @} */