libnl 1.1
|
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-2006 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 nl_error(EINVAL, "FIFO options size mismatch"); 00064 00065 fifo = fifo_alloc(qdisc); 00066 if (!fifo) 00067 return nl_errno(ENOMEM); 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 int pfifo_dump_brief(struct rtnl_qdisc *qdisc, 00082 struct nl_dump_params *p, int line) 00083 { 00084 struct rtnl_fifo *fifo = fifo_qdisc(qdisc); 00085 00086 if (fifo) 00087 dp_dump(p, " limit %u packets", fifo->qf_limit); 00088 00089 return line; 00090 } 00091 00092 static int bfifo_dump_brief(struct rtnl_qdisc *qdisc, 00093 struct nl_dump_params *p, int line) 00094 { 00095 struct rtnl_fifo *fifo = fifo_qdisc(qdisc); 00096 00097 if (fifo) { 00098 char *unit; 00099 double r; 00100 00101 r = nl_cancel_down_bytes(fifo->qf_limit, &unit); 00102 dp_dump(p, " limit %.1f%s", r, unit); 00103 } 00104 00105 return line; 00106 } 00107 00108 static struct nl_msg *fifo_get_opts(struct rtnl_qdisc *qdisc) 00109 { 00110 struct rtnl_fifo *fifo; 00111 struct tc_fifo_qopt opts; 00112 struct nl_msg *msg; 00113 00114 fifo = fifo_qdisc(qdisc); 00115 if (!fifo || !(fifo->qf_mask & SCH_FIFO_ATTR_LIMIT)) 00116 return NULL; 00117 00118 msg = nlmsg_alloc(); 00119 if (!msg) 00120 goto errout; 00121 00122 memset(&opts, 0, sizeof(opts)); 00123 opts.limit = fifo->qf_limit; 00124 00125 if (nlmsg_append(msg, &opts, sizeof(opts), NL_DONTPAD) < 0) 00126 goto errout; 00127 00128 return msg; 00129 errout: 00130 nlmsg_free(msg); 00131 return NULL; 00132 } 00133 00134 /** 00135 * @name Attribute Modification 00136 * @{ 00137 */ 00138 00139 /** 00140 * Set limit of FIFO qdisc. 00141 * @arg qdisc FIFO qdisc to be modified. 00142 * @arg limit New limit. 00143 * @return 0 on success or a negative error code. 00144 */ 00145 int rtnl_qdisc_fifo_set_limit(struct rtnl_qdisc *qdisc, int limit) 00146 { 00147 struct rtnl_fifo *fifo; 00148 00149 fifo = fifo_alloc(qdisc); 00150 if (!fifo) 00151 return nl_errno(ENOMEM); 00152 00153 fifo->qf_limit = limit; 00154 fifo->qf_mask |= SCH_FIFO_ATTR_LIMIT; 00155 00156 return 0; 00157 } 00158 00159 /** 00160 * Get limit of a FIFO qdisc. 00161 * @arg qdisc FIFO qdisc. 00162 * @return Numeric limit or a negative error code. 00163 */ 00164 int rtnl_qdisc_fifo_get_limit(struct rtnl_qdisc *qdisc) 00165 { 00166 struct rtnl_fifo *fifo; 00167 00168 fifo = fifo_qdisc(qdisc); 00169 if (fifo && fifo->qf_mask & SCH_FIFO_ATTR_LIMIT) 00170 return fifo->qf_limit; 00171 else 00172 return nl_errno(ENOMEM); 00173 } 00174 00175 /** @} */ 00176 00177 static struct rtnl_qdisc_ops pfifo_ops = { 00178 .qo_kind = "pfifo", 00179 .qo_msg_parser = fifo_msg_parser, 00180 .qo_free_data = fifo_free_data, 00181 .qo_dump[NL_DUMP_BRIEF] = pfifo_dump_brief, 00182 .qo_get_opts = fifo_get_opts, 00183 }; 00184 00185 static struct rtnl_qdisc_ops bfifo_ops = { 00186 .qo_kind = "bfifo", 00187 .qo_msg_parser = fifo_msg_parser, 00188 .qo_free_data = fifo_free_data, 00189 .qo_dump[NL_DUMP_BRIEF] = bfifo_dump_brief, 00190 .qo_get_opts = fifo_get_opts, 00191 }; 00192 00193 static void __init fifo_init(void) 00194 { 00195 rtnl_qdisc_register(&pfifo_ops); 00196 rtnl_qdisc_register(&bfifo_ops); 00197 } 00198 00199 static void __exit fifo_exit(void) 00200 { 00201 rtnl_qdisc_unregister(&pfifo_ops); 00202 rtnl_qdisc_unregister(&bfifo_ops); 00203 } 00204 00205 /** @} */