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 (at) 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 37 static 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 46 static 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 89 static 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 111 static 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 132 nla_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 */ 148 int 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 */ 166 int 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 */ 185 int 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 */ 203 uint32_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 */ 220 int 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 */ 238 uint32_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 */ 255 int 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 */ 273 uint32_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 */ 290 int 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 */ 308 int 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 */ 326 int 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 */ 344 int 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 358 static 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 367 static void __init fq_codel_init(void) 368 { 369 rtnl_tc_register(&fq_codel_ops); 370 } 371 372 static void __exit fq_codel_exit(void) 373 { 374 rtnl_tc_unregister(&fq_codel_ops); 375 } 376 377 /** @} */ 378