netem.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908
  1. /*
  2. * lib/route/qdisc/netem.c Network Emulator Qdisc
  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-2011 Thomas Graf <tgraf@suug.ch>
  10. */
  11. /**
  12. * @ingroup qdisc
  13. * @defgroup qdisc_netem Network Emulator
  14. * @brief
  15. *
  16. * For further documentation see http://linux-net.osdl.org/index.php/Netem
  17. * @{
  18. */
  19. #include <netlink-private/netlink.h>
  20. #include <netlink-private/tc.h>
  21. #include <netlink/netlink.h>
  22. #include <netlink/utils.h>
  23. #include <netlink-private/route/tc-api.h>
  24. #include <netlink/route/qdisc.h>
  25. #include <netlink/route/qdisc/netem.h>
  26. /** @cond SKIP */
  27. #define SCH_NETEM_ATTR_LATENCY 0x0001
  28. #define SCH_NETEM_ATTR_LIMIT 0x0002
  29. #define SCH_NETEM_ATTR_LOSS 0x0004
  30. #define SCH_NETEM_ATTR_GAP 0x0008
  31. #define SCH_NETEM_ATTR_DUPLICATE 0x0010
  32. #define SCH_NETEM_ATTR_JITTER 0x0020
  33. #define SCH_NETEM_ATTR_DELAY_CORR 0x0040
  34. #define SCH_NETEM_ATTR_LOSS_CORR 0x0080
  35. #define SCH_NETEM_ATTR_DUP_CORR 0x0100
  36. #define SCH_NETEM_ATTR_RO_PROB 0x0200
  37. #define SCH_NETEM_ATTR_RO_CORR 0x0400
  38. #define SCH_NETEM_ATTR_CORRUPT_PROB 0x0800
  39. #define SCH_NETEM_ATTR_CORRUPT_CORR 0x1000
  40. #define SCH_NETEM_ATTR_DIST 0x2000
  41. /** @endcond */
  42. static struct nla_policy netem_policy[TCA_NETEM_MAX+1] = {
  43. [TCA_NETEM_CORR] = { .minlen = sizeof(struct tc_netem_corr) },
  44. [TCA_NETEM_REORDER] = { .minlen = sizeof(struct tc_netem_reorder) },
  45. [TCA_NETEM_CORRUPT] = { .minlen = sizeof(struct tc_netem_corrupt) },
  46. };
  47. static int netem_msg_parser(struct rtnl_tc *tc, void *data)
  48. {
  49. struct rtnl_netem *netem = data;
  50. struct tc_netem_qopt *opts;
  51. int len, err = 0;
  52. if (tc->tc_opts->d_size < sizeof(*opts))
  53. return -NLE_INVAL;
  54. opts = (struct tc_netem_qopt *) tc->tc_opts->d_data;
  55. netem->qnm_latency = opts->latency;
  56. netem->qnm_limit = opts->limit;
  57. netem->qnm_loss = opts->loss;
  58. netem->qnm_gap = opts->gap;
  59. netem->qnm_duplicate = opts->duplicate;
  60. netem->qnm_jitter = opts->jitter;
  61. netem->qnm_mask = (SCH_NETEM_ATTR_LATENCY | SCH_NETEM_ATTR_LIMIT |
  62. SCH_NETEM_ATTR_LOSS | SCH_NETEM_ATTR_GAP |
  63. SCH_NETEM_ATTR_DUPLICATE | SCH_NETEM_ATTR_JITTER);
  64. len = tc->tc_opts->d_size - sizeof(*opts);
  65. if (len > 0) {
  66. struct nlattr *tb[TCA_NETEM_MAX+1];
  67. err = nla_parse(tb, TCA_NETEM_MAX, (struct nlattr *)
  68. (tc->tc_opts->d_data + sizeof(*opts)),
  69. len, netem_policy);
  70. if (err < 0) {
  71. free(netem);
  72. return err;
  73. }
  74. if (tb[TCA_NETEM_CORR]) {
  75. struct tc_netem_corr cor;
  76. nla_memcpy(&cor, tb[TCA_NETEM_CORR], sizeof(cor));
  77. netem->qnm_corr.nmc_delay = cor.delay_corr;
  78. netem->qnm_corr.nmc_loss = cor.loss_corr;
  79. netem->qnm_corr.nmc_duplicate = cor.dup_corr;
  80. netem->qnm_mask |= (SCH_NETEM_ATTR_DELAY_CORR |
  81. SCH_NETEM_ATTR_LOSS_CORR |
  82. SCH_NETEM_ATTR_DUP_CORR);
  83. }
  84. if (tb[TCA_NETEM_REORDER]) {
  85. struct tc_netem_reorder ro;
  86. nla_memcpy(&ro, tb[TCA_NETEM_REORDER], sizeof(ro));
  87. netem->qnm_ro.nmro_probability = ro.probability;
  88. netem->qnm_ro.nmro_correlation = ro.correlation;
  89. netem->qnm_mask |= (SCH_NETEM_ATTR_RO_PROB |
  90. SCH_NETEM_ATTR_RO_CORR);
  91. }
  92. if (tb[TCA_NETEM_CORRUPT]) {
  93. struct tc_netem_corrupt corrupt;
  94. nla_memcpy(&corrupt, tb[TCA_NETEM_CORRUPT], sizeof(corrupt));
  95. netem->qnm_crpt.nmcr_probability = corrupt.probability;
  96. netem->qnm_crpt.nmcr_correlation = corrupt.correlation;
  97. netem->qnm_mask |= (SCH_NETEM_ATTR_CORRUPT_PROB |
  98. SCH_NETEM_ATTR_CORRUPT_CORR);
  99. }
  100. /* sch_netem does not currently dump TCA_NETEM_DELAY_DIST */
  101. netem->qnm_dist.dist_data = NULL;
  102. netem->qnm_dist.dist_size = 0;
  103. }
  104. return 0;
  105. }
  106. static void netem_free_data(struct rtnl_tc *tc, void *data)
  107. {
  108. struct rtnl_netem *netem = data;
  109. if (!netem)
  110. return;
  111. free(netem->qnm_dist.dist_data);
  112. }
  113. static void netem_dump_line(struct rtnl_tc *tc, void *data,
  114. struct nl_dump_params *p)
  115. {
  116. struct rtnl_netem *netem = data;
  117. if (netem)
  118. nl_dump(p, "limit %d", netem->qnm_limit);
  119. }
  120. static int netem_msg_fill_raw(struct rtnl_tc *tc, void *data,
  121. struct nl_msg *msg)
  122. {
  123. int err = 0;
  124. struct tc_netem_qopt opts;
  125. struct tc_netem_corr cor;
  126. struct tc_netem_reorder reorder;
  127. struct tc_netem_corrupt corrupt;
  128. struct rtnl_netem *netem = data;
  129. unsigned char set_correlation = 0, set_reorder = 0,
  130. set_corrupt = 0, set_dist = 0;
  131. if (!netem)
  132. BUG();
  133. memset(&opts, 0, sizeof(opts));
  134. memset(&cor, 0, sizeof(cor));
  135. memset(&reorder, 0, sizeof(reorder));
  136. memset(&corrupt, 0, sizeof(corrupt));
  137. msg->nm_nlh->nlmsg_flags |= NLM_F_REQUEST;
  138. if ( netem->qnm_ro.nmro_probability != 0 ) {
  139. if (netem->qnm_latency == 0) {
  140. return -NLE_MISSING_ATTR;
  141. }
  142. if (netem->qnm_gap == 0) netem->qnm_gap = 1;
  143. }
  144. else if ( netem->qnm_gap ) {
  145. return -NLE_MISSING_ATTR;
  146. }
  147. if ( netem->qnm_corr.nmc_delay != 0 ) {
  148. if ( netem->qnm_latency == 0 || netem->qnm_jitter == 0) {
  149. return -NLE_MISSING_ATTR;
  150. }
  151. set_correlation = 1;
  152. }
  153. if ( netem->qnm_corr.nmc_loss != 0 ) {
  154. if ( netem->qnm_loss == 0 ) {
  155. return -NLE_MISSING_ATTR;
  156. }
  157. set_correlation = 1;
  158. }
  159. if ( netem->qnm_corr.nmc_duplicate != 0 ) {
  160. if ( netem->qnm_duplicate == 0 ) {
  161. return -NLE_MISSING_ATTR;
  162. }
  163. set_correlation = 1;
  164. }
  165. if ( netem->qnm_ro.nmro_probability != 0 ) set_reorder = 1;
  166. else if ( netem->qnm_ro.nmro_correlation != 0 ) {
  167. return -NLE_MISSING_ATTR;
  168. }
  169. if ( netem->qnm_crpt.nmcr_probability != 0 ) set_corrupt = 1;
  170. else if ( netem->qnm_crpt.nmcr_correlation != 0 ) {
  171. return -NLE_MISSING_ATTR;
  172. }
  173. if ( netem->qnm_dist.dist_data && netem->qnm_dist.dist_size ) {
  174. if (netem->qnm_latency == 0 || netem->qnm_jitter == 0) {
  175. return -NLE_MISSING_ATTR;
  176. }
  177. else {
  178. /* Resize to accomodate the large distribution table */
  179. int new_msg_len = msg->nm_size + netem->qnm_dist.dist_size *
  180. sizeof(netem->qnm_dist.dist_data[0]);
  181. msg->nm_nlh = (struct nlmsghdr *) realloc(msg->nm_nlh, new_msg_len);
  182. if ( msg->nm_nlh == NULL )
  183. return -NLE_NOMEM;
  184. msg->nm_size = new_msg_len;
  185. set_dist = 1;
  186. }
  187. }
  188. opts.latency = netem->qnm_latency;
  189. opts.limit = netem->qnm_limit ? netem->qnm_limit : 1000;
  190. opts.loss = netem->qnm_loss;
  191. opts.gap = netem->qnm_gap;
  192. opts.duplicate = netem->qnm_duplicate;
  193. opts.jitter = netem->qnm_jitter;
  194. NLA_PUT(msg, TCA_OPTIONS, sizeof(opts), &opts);
  195. if ( set_correlation ) {
  196. cor.delay_corr = netem->qnm_corr.nmc_delay;
  197. cor.loss_corr = netem->qnm_corr.nmc_loss;
  198. cor.dup_corr = netem->qnm_corr.nmc_duplicate;
  199. NLA_PUT(msg, TCA_NETEM_CORR, sizeof(cor), &cor);
  200. }
  201. if ( set_reorder ) {
  202. reorder.probability = netem->qnm_ro.nmro_probability;
  203. reorder.correlation = netem->qnm_ro.nmro_correlation;
  204. NLA_PUT(msg, TCA_NETEM_REORDER, sizeof(reorder), &reorder);
  205. }
  206. if ( set_corrupt ) {
  207. corrupt.probability = netem->qnm_crpt.nmcr_probability;
  208. corrupt.correlation = netem->qnm_crpt.nmcr_correlation;
  209. NLA_PUT(msg, TCA_NETEM_CORRUPT, sizeof(corrupt), &corrupt);
  210. }
  211. if ( set_dist ) {
  212. NLA_PUT(msg, TCA_NETEM_DELAY_DIST,
  213. netem->qnm_dist.dist_size * sizeof(netem->qnm_dist.dist_data[0]),
  214. netem->qnm_dist.dist_data);
  215. }
  216. /* Length specified in the TCA_OPTIONS section must span the entire
  217. * remainder of the message. That's just the way that sch_netem expects it.
  218. * Maybe there's a more succinct way to do this at a higher level.
  219. */
  220. struct nlattr* head = (struct nlattr *)(NLMSG_DATA(msg->nm_nlh) +
  221. NLMSG_LENGTH(sizeof(struct tcmsg)) - NLMSG_ALIGNTO);
  222. struct nlattr* tail = (struct nlattr *)(((void *) (msg->nm_nlh)) +
  223. NLMSG_ALIGN(msg->nm_nlh->nlmsg_len));
  224. int old_len = head->nla_len;
  225. head->nla_len = (void *)tail - (void *)head;
  226. msg->nm_nlh->nlmsg_len += (head->nla_len - old_len);
  227. return err;
  228. nla_put_failure:
  229. return -NLE_MSGSIZE;
  230. }
  231. /**
  232. * @name Queue Limit
  233. * @{
  234. */
  235. /**
  236. * Set limit of netem qdisc.
  237. * @arg qdisc Netem qdisc to be modified.
  238. * @arg limit New limit in bytes.
  239. * @return 0 on success or a negative error code.
  240. */
  241. void rtnl_netem_set_limit(struct rtnl_qdisc *qdisc, int limit)
  242. {
  243. struct rtnl_netem *netem;
  244. if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
  245. BUG();
  246. netem->qnm_limit = limit;
  247. netem->qnm_mask |= SCH_NETEM_ATTR_LIMIT;
  248. }
  249. /**
  250. * Get limit of netem qdisc.
  251. * @arg qdisc Netem qdisc.
  252. * @return Limit in bytes or a negative error code.
  253. */
  254. int rtnl_netem_get_limit(struct rtnl_qdisc *qdisc)
  255. {
  256. struct rtnl_netem *netem;
  257. if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
  258. return -NLE_NOMEM;
  259. if (netem->qnm_mask & SCH_NETEM_ATTR_LIMIT)
  260. return netem->qnm_limit;
  261. else
  262. return -NLE_NOATTR;
  263. }
  264. /** @} */
  265. /**
  266. * @name Packet Re-ordering
  267. * @{
  268. */
  269. /**
  270. * Set re-ordering gap of netem qdisc.
  271. * @arg qdisc Netem qdisc to be modified.
  272. * @arg gap New gap in number of packets.
  273. * @return 0 on success or a negative error code.
  274. */
  275. void rtnl_netem_set_gap(struct rtnl_qdisc *qdisc, int gap)
  276. {
  277. struct rtnl_netem *netem;
  278. if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
  279. BUG();
  280. netem->qnm_gap = gap;
  281. netem->qnm_mask |= SCH_NETEM_ATTR_GAP;
  282. }
  283. /**
  284. * Get re-ordering gap of netem qdisc.
  285. * @arg qdisc Netem qdisc.
  286. * @return Re-ordering gap in packets or a negative error code.
  287. */
  288. int rtnl_netem_get_gap(struct rtnl_qdisc *qdisc)
  289. {
  290. struct rtnl_netem *netem;
  291. if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
  292. return -NLE_NOMEM;
  293. if (netem->qnm_mask & SCH_NETEM_ATTR_GAP)
  294. return netem->qnm_gap;
  295. else
  296. return -NLE_NOATTR;
  297. }
  298. /**
  299. * Set re-ordering probability of netem qdisc.
  300. * @arg qdisc Netem qdisc to be modified.
  301. * @arg prob New re-ordering probability.
  302. * @return 0 on success or a negative error code.
  303. */
  304. void rtnl_netem_set_reorder_probability(struct rtnl_qdisc *qdisc, int prob)
  305. {
  306. struct rtnl_netem *netem;
  307. if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
  308. BUG();
  309. netem->qnm_ro.nmro_probability = prob;
  310. netem->qnm_mask |= SCH_NETEM_ATTR_RO_PROB;
  311. }
  312. /**
  313. * Get re-ordering probability of netem qdisc.
  314. * @arg qdisc Netem qdisc.
  315. * @return Re-ordering probability or a negative error code.
  316. */
  317. int rtnl_netem_get_reorder_probability(struct rtnl_qdisc *qdisc)
  318. {
  319. struct rtnl_netem *netem;
  320. if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
  321. return -NLE_NOMEM;
  322. if (netem->qnm_mask & SCH_NETEM_ATTR_RO_PROB)
  323. return netem->qnm_ro.nmro_probability;
  324. else
  325. return -NLE_NOATTR;
  326. }
  327. /**
  328. * Set re-order correlation probability of netem qdisc.
  329. * @arg qdisc Netem qdisc to be modified.
  330. * @arg prob New re-ordering correlation probability.
  331. * @return 0 on success or a negative error code.
  332. */
  333. void rtnl_netem_set_reorder_correlation(struct rtnl_qdisc *qdisc, int prob)
  334. {
  335. struct rtnl_netem *netem;
  336. if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
  337. BUG();
  338. netem->qnm_ro.nmro_correlation = prob;
  339. netem->qnm_mask |= SCH_NETEM_ATTR_RO_CORR;
  340. }
  341. /**
  342. * Get re-ordering correlation probability of netem qdisc.
  343. * @arg qdisc Netem qdisc.
  344. * @return Re-ordering correlation probability or a negative error code.
  345. */
  346. int rtnl_netem_get_reorder_correlation(struct rtnl_qdisc *qdisc)
  347. {
  348. struct rtnl_netem *netem;
  349. if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
  350. return -NLE_NOMEM;
  351. if (netem->qnm_mask & SCH_NETEM_ATTR_RO_CORR)
  352. return netem->qnm_ro.nmro_correlation;
  353. else
  354. return -NLE_NOATTR;
  355. }
  356. /** @} */
  357. /**
  358. * @name Corruption
  359. * @{
  360. */
  361. /**
  362. * Set corruption probability of netem qdisc.
  363. * @arg qdisc Netem qdisc to be modified.
  364. * @arg prob New corruption probability.
  365. * @return 0 on success or a negative error code.
  366. */
  367. void rtnl_netem_set_corruption_probability(struct rtnl_qdisc *qdisc, int prob)
  368. {
  369. struct rtnl_netem *netem;
  370. if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
  371. BUG();
  372. netem->qnm_crpt.nmcr_probability = prob;
  373. netem->qnm_mask |= SCH_NETEM_ATTR_CORRUPT_PROB;
  374. }
  375. /**
  376. * Get corruption probability of netem qdisc.
  377. * @arg qdisc Netem qdisc.
  378. * @return Corruption probability or a negative error code.
  379. */
  380. int rtnl_netem_get_corruption_probability(struct rtnl_qdisc *qdisc)
  381. {
  382. struct rtnl_netem *netem;
  383. if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
  384. BUG();
  385. if (netem->qnm_mask & SCH_NETEM_ATTR_CORRUPT_PROB)
  386. return netem->qnm_crpt.nmcr_probability;
  387. else
  388. return -NLE_NOATTR;
  389. }
  390. /**
  391. * Set corruption correlation probability of netem qdisc.
  392. * @arg qdisc Netem qdisc to be modified.
  393. * @arg prob New corruption correlation probability.
  394. * @return 0 on success or a negative error code.
  395. */
  396. void rtnl_netem_set_corruption_correlation(struct rtnl_qdisc *qdisc, int prob)
  397. {
  398. struct rtnl_netem *netem;
  399. if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
  400. BUG();
  401. netem->qnm_crpt.nmcr_correlation = prob;
  402. netem->qnm_mask |= SCH_NETEM_ATTR_CORRUPT_CORR;
  403. }
  404. /**
  405. * Get corruption correlation probability of netem qdisc.
  406. * @arg qdisc Netem qdisc.
  407. * @return Corruption correlation probability or a negative error code.
  408. */
  409. int rtnl_netem_get_corruption_correlation(struct rtnl_qdisc *qdisc)
  410. {
  411. struct rtnl_netem *netem;
  412. if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
  413. BUG();
  414. if (netem->qnm_mask & SCH_NETEM_ATTR_CORRUPT_CORR)
  415. return netem->qnm_crpt.nmcr_correlation;
  416. else
  417. return -NLE_NOATTR;
  418. }
  419. /** @} */
  420. /**
  421. * @name Packet Loss
  422. * @{
  423. */
  424. /**
  425. * Set packet loss probability of netem qdisc.
  426. * @arg qdisc Netem qdisc to be modified.
  427. * @arg prob New packet loss probability.
  428. * @return 0 on success or a negative error code.
  429. */
  430. void rtnl_netem_set_loss(struct rtnl_qdisc *qdisc, int prob)
  431. {
  432. struct rtnl_netem *netem;
  433. if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
  434. BUG();
  435. netem->qnm_loss = prob;
  436. netem->qnm_mask |= SCH_NETEM_ATTR_LOSS;
  437. }
  438. /**
  439. * Get packet loss probability of netem qdisc.
  440. * @arg qdisc Netem qdisc.
  441. * @return Packet loss probability or a negative error code.
  442. */
  443. int rtnl_netem_get_loss(struct rtnl_qdisc *qdisc)
  444. {
  445. struct rtnl_netem *netem;
  446. if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
  447. BUG();
  448. if (netem->qnm_mask & SCH_NETEM_ATTR_LOSS)
  449. return netem->qnm_loss;
  450. else
  451. return -NLE_NOATTR;
  452. }
  453. /**
  454. * Set packet loss correlation probability of netem qdisc.
  455. * @arg qdisc Netem qdisc to be modified.
  456. * @arg prob New packet loss correlation.
  457. * @return 0 on success or a negative error code.
  458. */
  459. void rtnl_netem_set_loss_correlation(struct rtnl_qdisc *qdisc, int prob)
  460. {
  461. struct rtnl_netem *netem;
  462. if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
  463. BUG();
  464. netem->qnm_corr.nmc_loss = prob;
  465. netem->qnm_mask |= SCH_NETEM_ATTR_LOSS_CORR;
  466. }
  467. /**
  468. * Get packet loss correlation probability of netem qdisc.
  469. * @arg qdisc Netem qdisc.
  470. * @return Packet loss correlation probability or a negative error code.
  471. */
  472. int rtnl_netem_get_loss_correlation(struct rtnl_qdisc *qdisc)
  473. {
  474. struct rtnl_netem *netem;
  475. if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
  476. BUG();
  477. if (netem->qnm_mask & SCH_NETEM_ATTR_LOSS_CORR)
  478. return netem->qnm_corr.nmc_loss;
  479. else
  480. return -NLE_NOATTR;
  481. }
  482. /** @} */
  483. /**
  484. * @name Packet Duplication
  485. * @{
  486. */
  487. /**
  488. * Set packet duplication probability of netem qdisc.
  489. * @arg qdisc Netem qdisc to be modified.
  490. * @arg prob New packet duplication probability.
  491. * @return 0 on success or a negative error code.
  492. */
  493. void rtnl_netem_set_duplicate(struct rtnl_qdisc *qdisc, int prob)
  494. {
  495. struct rtnl_netem *netem;
  496. if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
  497. BUG();
  498. netem->qnm_duplicate = prob;
  499. netem->qnm_mask |= SCH_NETEM_ATTR_DUPLICATE;
  500. }
  501. /**
  502. * Get packet duplication probability of netem qdisc.
  503. * @arg qdisc Netem qdisc.
  504. * @return Packet duplication probability or a negative error code.
  505. */
  506. int rtnl_netem_get_duplicate(struct rtnl_qdisc *qdisc)
  507. {
  508. struct rtnl_netem *netem;
  509. if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
  510. BUG();
  511. if (netem->qnm_mask & SCH_NETEM_ATTR_DUPLICATE)
  512. return netem->qnm_duplicate;
  513. else
  514. return -NLE_NOATTR;
  515. }
  516. /**
  517. * Set packet duplication correlation probability of netem qdisc.
  518. * @arg qdisc Netem qdisc to be modified.
  519. * @arg prob New packet duplication correlation probability.
  520. * @return 0 on sucess or a negative error code.
  521. */
  522. void rtnl_netem_set_duplicate_correlation(struct rtnl_qdisc *qdisc, int prob)
  523. {
  524. struct rtnl_netem *netem;
  525. if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
  526. BUG();
  527. netem->qnm_corr.nmc_duplicate = prob;
  528. netem->qnm_mask |= SCH_NETEM_ATTR_DUP_CORR;
  529. }
  530. /**
  531. * Get packet duplication correlation probability of netem qdisc.
  532. * @arg qdisc Netem qdisc.
  533. * @return Packet duplication correlation probability or a negative error code.
  534. */
  535. int rtnl_netem_get_duplicate_correlation(struct rtnl_qdisc *qdisc)
  536. {
  537. struct rtnl_netem *netem;
  538. if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
  539. BUG();
  540. if (netem->qnm_mask & SCH_NETEM_ATTR_DUP_CORR)
  541. return netem->qnm_corr.nmc_duplicate;
  542. else
  543. return -NLE_NOATTR;
  544. }
  545. /** @} */
  546. /**
  547. * @name Packet Delay
  548. * @{
  549. */
  550. /**
  551. * Set packet delay of netem qdisc.
  552. * @arg qdisc Netem qdisc to be modified.
  553. * @arg delay New packet delay in micro seconds.
  554. * @return 0 on success or a negative error code.
  555. */
  556. void rtnl_netem_set_delay(struct rtnl_qdisc *qdisc, int delay)
  557. {
  558. struct rtnl_netem *netem;
  559. if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
  560. BUG();
  561. netem->qnm_latency = nl_us2ticks(delay);
  562. netem->qnm_mask |= SCH_NETEM_ATTR_LATENCY;
  563. }
  564. /**
  565. * Get packet delay of netem qdisc.
  566. * @arg qdisc Netem qdisc.
  567. * @return Packet delay in micro seconds or a negative error code.
  568. */
  569. int rtnl_netem_get_delay(struct rtnl_qdisc *qdisc)
  570. {
  571. struct rtnl_netem *netem;
  572. if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
  573. BUG();
  574. if (netem->qnm_mask & SCH_NETEM_ATTR_LATENCY)
  575. return nl_ticks2us(netem->qnm_latency);
  576. else
  577. return -NLE_NOATTR;
  578. }
  579. /**
  580. * Set packet delay jitter of netem qdisc.
  581. * @arg qdisc Netem qdisc to be modified.
  582. * @arg jitter New packet delay jitter in micro seconds.
  583. * @return 0 on success or a negative error code.
  584. */
  585. void rtnl_netem_set_jitter(struct rtnl_qdisc *qdisc, int jitter)
  586. {
  587. struct rtnl_netem *netem;
  588. if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
  589. BUG();
  590. netem->qnm_jitter = nl_us2ticks(jitter);
  591. netem->qnm_mask |= SCH_NETEM_ATTR_JITTER;
  592. }
  593. /**
  594. * Get packet delay jitter of netem qdisc.
  595. * @arg qdisc Netem qdisc.
  596. * @return Packet delay jitter in micro seconds or a negative error code.
  597. */
  598. int rtnl_netem_get_jitter(struct rtnl_qdisc *qdisc)
  599. {
  600. struct rtnl_netem *netem;
  601. if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
  602. BUG();
  603. if (netem->qnm_mask & SCH_NETEM_ATTR_JITTER)
  604. return nl_ticks2us(netem->qnm_jitter);
  605. else
  606. return -NLE_NOATTR;
  607. }
  608. /**
  609. * Set packet delay correlation probability of netem qdisc.
  610. * @arg qdisc Netem qdisc to be modified.
  611. * @arg prob New packet delay correlation probability.
  612. */
  613. void rtnl_netem_set_delay_correlation(struct rtnl_qdisc *qdisc, int prob)
  614. {
  615. struct rtnl_netem *netem;
  616. if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
  617. BUG();
  618. netem->qnm_corr.nmc_delay = prob;
  619. netem->qnm_mask |= SCH_NETEM_ATTR_DELAY_CORR;
  620. }
  621. /**
  622. * Get packet delay correlation probability of netem qdisc.
  623. * @arg qdisc Netem qdisc.
  624. * @return Packet delay correlation probability or a negative error code.
  625. */
  626. int rtnl_netem_get_delay_correlation(struct rtnl_qdisc *qdisc)
  627. {
  628. struct rtnl_netem *netem;
  629. if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
  630. BUG();
  631. if (netem->qnm_mask & SCH_NETEM_ATTR_DELAY_CORR)
  632. return netem->qnm_corr.nmc_delay;
  633. else
  634. return -NLE_NOATTR;
  635. }
  636. /**
  637. * Get the size of the distribution table.
  638. * @arg qdisc Netem qdisc.
  639. * @return Distribution table size or a negative error code.
  640. */
  641. int rtnl_netem_get_delay_distribution_size(struct rtnl_qdisc *qdisc)
  642. {
  643. struct rtnl_netem *netem;
  644. if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
  645. BUG();
  646. if (netem->qnm_mask & SCH_NETEM_ATTR_DIST)
  647. return netem->qnm_dist.dist_size;
  648. else
  649. return -NLE_NOATTR;
  650. }
  651. /**
  652. * Get a pointer to the distribution table.
  653. * @arg qdisc Netem qdisc.
  654. * @arg dist_ptr The pointer to set.
  655. * @return Negative error code on failure or 0 on success.
  656. */
  657. int rtnl_netem_get_delay_distribution(struct rtnl_qdisc *qdisc, int16_t **dist_ptr)
  658. {
  659. struct rtnl_netem *netem;
  660. if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
  661. BUG();
  662. if (netem->qnm_mask & SCH_NETEM_ATTR_DIST) {
  663. *dist_ptr = netem->qnm_dist.dist_data;
  664. return 0;
  665. } else
  666. return -NLE_NOATTR;
  667. }
  668. /**
  669. * Set the delay distribution. Latency/jitter must be set before applying.
  670. * @arg qdisc Netem qdisc.
  671. * @arg dist_type The name of the distribution (type, file, path/file).
  672. * @return 0 on success, error code on failure.
  673. */
  674. int rtnl_netem_set_delay_distribution(struct rtnl_qdisc *qdisc, const char *dist_type) {
  675. struct rtnl_netem *netem;
  676. if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
  677. BUG();
  678. FILE *f;
  679. int n = 0;
  680. size_t i;
  681. size_t len = 2048;
  682. char *line;
  683. char name[NAME_MAX];
  684. char dist_suffix[] = ".dist";
  685. /* If the given filename already ends in .dist, don't append it later */
  686. char *test_suffix = strstr(dist_type, dist_suffix);
  687. if (test_suffix != NULL && strlen(test_suffix) == 5)
  688. strcpy(dist_suffix, "");
  689. /* Check several locations for the dist file */
  690. char *test_path[] = { "", "./", "/usr/lib/tc/", "/usr/local/lib/tc/" };
  691. for (i = 0; i < ARRAY_SIZE(test_path); i++) {
  692. snprintf(name, NAME_MAX, "%s%s%s", test_path[i], dist_type, dist_suffix);
  693. if ((f = fopen(name, "r")))
  694. break;
  695. }
  696. if ( f == NULL )
  697. return -nl_syserr2nlerr(errno);
  698. netem->qnm_dist.dist_data = (int16_t *) calloc (MAXDIST, sizeof(int16_t));
  699. line = (char *) calloc (sizeof(char), len + 1);
  700. while (getline(&line, &len, f) != -1) {
  701. char *p, *endp;
  702. if (*line == '\n' || *line == '#')
  703. continue;
  704. for (p = line; ; p = endp) {
  705. long x = strtol(p, &endp, 0);
  706. if (endp == p) break;
  707. if (n >= MAXDIST) {
  708. free(line);
  709. fclose(f);
  710. return -NLE_INVAL;
  711. }
  712. netem->qnm_dist.dist_data[n++] = x;
  713. }
  714. }
  715. free(line);
  716. netem->qnm_dist.dist_size = n;
  717. netem->qnm_mask |= SCH_NETEM_ATTR_DIST;
  718. fclose(f);
  719. return 0;
  720. }
  721. /** @} */
  722. static struct rtnl_tc_ops netem_ops = {
  723. .to_kind = "netem",
  724. .to_type = RTNL_TC_TYPE_QDISC,
  725. .to_size = sizeof(struct rtnl_netem),
  726. .to_msg_parser = netem_msg_parser,
  727. .to_free_data = netem_free_data,
  728. .to_dump[NL_DUMP_LINE] = netem_dump_line,
  729. .to_msg_fill_raw = netem_msg_fill_raw,
  730. };
  731. static void __init netem_init(void)
  732. {
  733. rtnl_tc_register(&netem_ops);
  734. }
  735. static void __exit netem_exit(void)
  736. {
  737. rtnl_tc_unregister(&netem_ops);
  738. }
  739. /** @} */