1/* 2 * lib/route/qdisc/fq_codel.c fq_codel 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) 2013 Cong Wang <xiyou.wangcong@gmail.com> 10 */ 11 12/** 13 * @ingroup qdisc 14 * @defgroup qdisc_fq_codel Fair Queue CoDel 15 * @brief 16 * 17 * @{ 18 */ 19 20#include <netlink-private/netlink.h> 21#include <netlink-private/tc.h> 22#include <netlink/netlink.h> 23#include <netlink-private/route/tc-api.h> 24#include <netlink/route/qdisc.h> 25#include <netlink/route/qdisc/fq_codel.h> 26#include <netlink/utils.h> 27 28/** @cond SKIP */ 29#define SCH_FQ_CODEL_ATTR_TARGET 0x1 30#define SCH_FQ_CODEL_ATTR_LIMIT 0x2 31#define SCH_FQ_CODEL_ATTR_INTERVAL 0x4 32#define SCH_FQ_CODEL_ATTR_FLOWS 0x8 33#define SCH_FQ_CODEL_ATTR_QUANTUM 0x10 34#define SCH_FQ_CODEL_ATTR_ECN 0x20 35/** @endcond */ 36 37static struct nla_policy fq_codel_policy[TCA_FQ_CODEL_MAX + 1] = { 38 [TCA_FQ_CODEL_TARGET] = { .type = NLA_U32 }, 39 [TCA_FQ_CODEL_LIMIT] = { .type = NLA_U32 }, 40 [TCA_FQ_CODEL_INTERVAL] = { .type = NLA_U32 }, 41 [TCA_FQ_CODEL_ECN] = { .type = NLA_U32 }, 42 [TCA_FQ_CODEL_FLOWS] = { .type = NLA_U32 }, 43 [TCA_FQ_CODEL_QUANTUM] = { .type = NLA_U32 }, 44}; 45 46static int fq_codel_msg_parser(struct rtnl_tc *tc, void *data) 47{ 48 struct rtnl_fq_codel *fq_codel = data; 49 struct nlattr *tb[TCA_FQ_CODEL_MAX + 1]; 50 int err; 51 52 err = tca_parse(tb, TCA_FQ_CODEL_MAX, tc, fq_codel_policy); 53 if (err < 0) 54 return err; 55 56 if (tb[TCA_FQ_CODEL_TARGET]) { 57 fq_codel->fq_target = nla_get_u32(tb[TCA_FQ_CODEL_TARGET]); 58 fq_codel->fq_mask |= SCH_FQ_CODEL_ATTR_TARGET; 59 } 60 61 if (tb[TCA_FQ_CODEL_INTERVAL]) { 62 fq_codel->fq_interval = nla_get_u32(tb[TCA_FQ_CODEL_INTERVAL]); 63 fq_codel->fq_mask |= SCH_FQ_CODEL_ATTR_INTERVAL; 64 } 65 66 if (tb[TCA_FQ_CODEL_LIMIT]) { 67 fq_codel->fq_limit = nla_get_u32(tb[TCA_FQ_CODEL_LIMIT]); 68 fq_codel->fq_mask |= SCH_FQ_CODEL_ATTR_LIMIT; 69 } 70 71 if (tb[TCA_FQ_CODEL_QUANTUM]) { 72 fq_codel->fq_quantum = nla_get_u32(tb[TCA_FQ_CODEL_QUANTUM]); 73 fq_codel->fq_mask |= SCH_FQ_CODEL_ATTR_QUANTUM; 74 } 75 76 if (tb[TCA_FQ_CODEL_FLOWS]) { 77 fq_codel->fq_flows = nla_get_u32(tb[TCA_FQ_CODEL_FLOWS]); 78 fq_codel->fq_mask |= SCH_FQ_CODEL_ATTR_FLOWS; 79 } 80 81 if (tb[TCA_FQ_CODEL_ECN]) { 82 fq_codel->fq_ecn = nla_get_u32(tb[TCA_FQ_CODEL_ECN]); 83 fq_codel->fq_mask |= SCH_FQ_CODEL_ATTR_ECN; 84 } 85 86 return 0; 87} 88 89static void fq_codel_dump_line(struct rtnl_tc *tc, void *data, 90 struct nl_dump_params *p) 91{ 92 struct rtnl_fq_codel *fq_codel = data; 93 94 if (!fq_codel) 95 return; 96 97 if (fq_codel->fq_mask & SCH_FQ_CODEL_ATTR_LIMIT) 98 nl_dump(p, " limit %u packets", fq_codel->fq_limit); 99 if (fq_codel->fq_mask & SCH_FQ_CODEL_ATTR_TARGET) 100 nl_dump(p, " target %u", fq_codel->fq_target); 101 if (fq_codel->fq_mask & SCH_FQ_CODEL_ATTR_INTERVAL) 102 nl_dump(p, " interval %u", fq_codel->fq_interval); 103 if (fq_codel->fq_mask & SCH_FQ_CODEL_ATTR_ECN) 104 nl_dump(p, " ecn %u", fq_codel->fq_ecn); 105 if (fq_codel->fq_mask & SCH_FQ_CODEL_ATTR_FLOWS) 106 nl_dump(p, " flows %u", fq_codel->fq_flows); 107 if (fq_codel->fq_mask & SCH_FQ_CODEL_ATTR_QUANTUM) 108 nl_dump(p, " quantum %u", fq_codel->fq_quantum); 109} 110 111static int fq_codel_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg) 112{ 113 struct rtnl_fq_codel *fq_codel = data; 114 115 if (!fq_codel) 116 return -NLE_INVAL; 117 118 if (fq_codel->fq_mask & SCH_FQ_CODEL_ATTR_LIMIT) 119 NLA_PUT_U32(msg, TCA_FQ_CODEL_LIMIT, fq_codel->fq_limit); 120 if (fq_codel->fq_mask & SCH_FQ_CODEL_ATTR_INTERVAL) 121 NLA_PUT_U32(msg, TCA_FQ_CODEL_INTERVAL, fq_codel->fq_interval); 122 if (fq_codel->fq_mask & SCH_FQ_CODEL_ATTR_TARGET) 123 NLA_PUT_U32(msg, TCA_FQ_CODEL_TARGET, fq_codel->fq_target); 124 if (fq_codel->fq_mask & SCH_FQ_CODEL_ATTR_QUANTUM) 125 NLA_PUT_U32(msg, TCA_FQ_CODEL_QUANTUM, fq_codel->fq_quantum); 126 if (fq_codel->fq_mask & SCH_FQ_CODEL_ATTR_FLOWS) 127 NLA_PUT_U32(msg, TCA_FQ_CODEL_FLOWS, fq_codel->fq_flows); 128 if (fq_codel->fq_mask & SCH_FQ_CODEL_ATTR_ECN) 129 NLA_PUT_U32(msg, TCA_FQ_CODEL_ECN, fq_codel->fq_ecn); 130 return 0; 131 132nla_put_failure: 133 return -NLE_MSGSIZE; 134 135} 136 137/** 138 * @name Attribute Modification 139 * @{ 140 */ 141 142/** 143 * Set limit of fq_codel qdisc. 144 * @arg qdisc fq_codel qdisc to be modified. 145 * @arg limit New limit. 146 * @return 0 on success or a negative error code. 147 */ 148int rtnl_qdisc_fq_codel_set_limit(struct rtnl_qdisc *qdisc, int limit) 149{ 150 struct rtnl_fq_codel *fq_codel; 151 152 if (!(fq_codel = rtnl_tc_data(TC_CAST(qdisc)))) 153 return -NLE_NOMEM; 154 155 fq_codel->fq_limit = limit; 156 fq_codel->fq_mask |= SCH_FQ_CODEL_ATTR_LIMIT; 157 158 return 0; 159} 160 161/** 162 * Get limit of a fq_codel qdisc. 163 * @arg qdisc fq_codel qdisc. 164 * @return Numeric limit or a negative error code. 165 */ 166int rtnl_qdisc_fq_codel_get_limit(struct rtnl_qdisc *qdisc) 167{ 168 struct rtnl_fq_codel *fq_codel; 169 170 if (!(fq_codel = rtnl_tc_data(TC_CAST(qdisc)))) 171 return -NLE_NOMEM; 172 173 if (fq_codel->fq_mask & SCH_FQ_CODEL_ATTR_LIMIT) 174 return fq_codel->fq_limit; 175 else 176 return -NLE_NOATTR; 177} 178 179/** 180 * Set target of fq_codel qdisc. 181 * @arg qdisc fq_codel qdisc to be modified. 182 * @arg target New target. 183 * @return 0 on success or a negative error code. 184 */ 185int rtnl_qdisc_fq_codel_set_target(struct rtnl_qdisc *qdisc, uint32_t target) 186{ 187 struct rtnl_fq_codel *fq_codel; 188 189 if (!(fq_codel = rtnl_tc_data(TC_CAST(qdisc)))) 190 return -NLE_NOMEM; 191 192 fq_codel->fq_target = target; 193 fq_codel->fq_mask |= SCH_FQ_CODEL_ATTR_TARGET; 194 195 return 0; 196} 197 198/** 199 * Get target of a fq_codel qdisc. 200 * @arg qdisc fq_codel qdisc. 201 * @return Numeric target or zero. 202 */ 203uint32_t rtnl_qdisc_fq_codel_get_target(struct rtnl_qdisc *qdisc) 204{ 205 struct rtnl_fq_codel *fq_codel; 206 207 if ((fq_codel = rtnl_tc_data(TC_CAST(qdisc))) && 208 fq_codel->fq_mask & SCH_FQ_CODEL_ATTR_TARGET) 209 return fq_codel->fq_target; 210 else 211 return 0; 212} 213 214/** 215 * Set interval of fq_codel qdisc. 216 * @arg qdisc fq_codel qdisc to be modified. 217 * @arg interval New interval. 218 * @return 0 on success or a negative error code. 219 */ 220int rtnl_qdisc_fq_codel_set_interval(struct rtnl_qdisc *qdisc, uint32_t interval) 221{ 222 struct rtnl_fq_codel *fq_codel; 223 224 if (!(fq_codel = rtnl_tc_data(TC_CAST(qdisc)))) 225 return -NLE_NOMEM; 226 227 fq_codel->fq_interval = interval; 228 fq_codel->fq_mask |= SCH_FQ_CODEL_ATTR_INTERVAL; 229 230 return 0; 231} 232 233/** 234 * Get target of a fq_codel qdisc. 235 * @arg qdisc fq_codel qdisc. 236 * @return Numeric interval or zero. 237 */ 238uint32_t rtnl_qdisc_fq_codel_get_interval(struct rtnl_qdisc *qdisc) 239{ 240 struct rtnl_fq_codel *fq_codel; 241 242 if ((fq_codel = rtnl_tc_data(TC_CAST(qdisc))) && 243 fq_codel->fq_mask & SCH_FQ_CODEL_ATTR_INTERVAL) 244 return fq_codel->fq_interval; 245 else 246 return 0; 247} 248 249/** 250 * Set quantum of fq_codel qdisc. 251 * @arg qdisc fq_codel qdisc to be modified. 252 * @arg quantum New quantum. 253 * @return 0 on success or a negative error code. 254 */ 255int rtnl_qdisc_fq_codel_set_quantum(struct rtnl_qdisc *qdisc, uint32_t quantum) 256{ 257 struct rtnl_fq_codel *fq_codel; 258 259 if (!(fq_codel = rtnl_tc_data(TC_CAST(qdisc)))) 260 return -NLE_NOMEM; 261 262 fq_codel->fq_quantum = quantum; 263 fq_codel->fq_mask |= SCH_FQ_CODEL_ATTR_QUANTUM; 264 265 return 0; 266} 267 268/** 269 * Get quantum of a fq_codel qdisc. 270 * @arg qdisc fq_codel qdisc. 271 * @return Numeric quantum or zero. 272 */ 273uint32_t rtnl_qdisc_fq_codel_get_quantum(struct rtnl_qdisc *qdisc) 274{ 275 struct rtnl_fq_codel *fq_codel; 276 277 if ((fq_codel = rtnl_tc_data(TC_CAST(qdisc))) && 278 (fq_codel->fq_mask & SCH_FQ_CODEL_ATTR_QUANTUM)) 279 return fq_codel->fq_quantum; 280 else 281 return 0; 282} 283 284/** 285 * Set flows of fq_codel qdisc. 286 * @arg qdisc fq_codel qdisc to be modified. 287 * @arg flows New flows value. 288 * @return 0 on success or a negative error code. 289 */ 290int rtnl_qdisc_fq_codel_set_flows(struct rtnl_qdisc *qdisc, int flows) 291{ 292 struct rtnl_fq_codel *fq_codel; 293 294 if (!(fq_codel = rtnl_tc_data(TC_CAST(qdisc)))) 295 return -NLE_NOMEM; 296 297 fq_codel->fq_flows = flows; 298 fq_codel->fq_mask |= SCH_FQ_CODEL_ATTR_FLOWS; 299 300 return 0; 301} 302 303/** 304 * Get flows of a fq_codel qdisc. 305 * @arg qdisc fq_codel qdisc. 306 * @return Numeric flows or a negative error code. 307 */ 308int rtnl_qdisc_fq_codel_get_flows(struct rtnl_qdisc *qdisc) 309{ 310 struct rtnl_fq_codel *fq_codel; 311 312 if (!(fq_codel = rtnl_tc_data(TC_CAST(qdisc)))) 313 return -NLE_NOMEM; 314 315 if (fq_codel->fq_mask & SCH_FQ_CODEL_ATTR_FLOWS) 316 return fq_codel->fq_flows; 317 else 318 return -NLE_NOATTR; 319} 320/** 321 * Set ecn of fq_codel qdisc. 322 * @arg qdisc fq_codel qdisc to be modified. 323 * @arg ecn New ecn value. 324 * @return 0 on success or a negative error code. 325 */ 326int rtnl_qdisc_fq_codel_set_ecn(struct rtnl_qdisc *qdisc, int ecn) 327{ 328 struct rtnl_fq_codel *fq_codel; 329 330 if (!(fq_codel = rtnl_tc_data(TC_CAST(qdisc)))) 331 return -NLE_NOMEM; 332 333 fq_codel->fq_ecn = ecn; 334 fq_codel->fq_mask |= SCH_FQ_CODEL_ATTR_ECN; 335 336 return 0; 337} 338 339/** 340 * Get ecn of a fq_codel qdisc. 341 * @arg qdisc fq_codel qdisc. 342 * @return Numeric ecn or a negative error code. 343 */ 344int rtnl_qdisc_fq_codel_get_ecn(struct rtnl_qdisc *qdisc) 345{ 346 struct rtnl_fq_codel *fq_codel; 347 348 if (!(fq_codel = rtnl_tc_data(TC_CAST(qdisc)))) 349 return -NLE_NOMEM; 350 351 if (fq_codel->fq_mask & SCH_FQ_CODEL_ATTR_ECN) 352 return fq_codel->fq_ecn; 353 else 354 return -NLE_NOATTR; 355} 356/** @} */ 357 358static struct rtnl_tc_ops fq_codel_ops = { 359 .to_kind = "fq_codel", 360 .to_type = RTNL_TC_TYPE_QDISC, 361 .to_size = sizeof(struct rtnl_fq_codel), 362 .to_msg_parser = fq_codel_msg_parser, 363 .to_dump[NL_DUMP_LINE] = fq_codel_dump_line, 364 .to_msg_fill = fq_codel_msg_fill, 365}; 366 367static void __init fq_codel_init(void) 368{ 369 rtnl_tc_register(&fq_codel_ops); 370} 371 372static void __exit fq_codel_exit(void) 373{ 374 rtnl_tc_unregister(&fq_codel_ops); 375} 376 377/** @} */ 378