dcbnl.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786
  1. /*
  2. * Copyright (c) 2008, Intel Corporation.
  3. *
  4. * This program is free software; you can redistribute it and/or modify it
  5. * under the terms and conditions of the GNU General Public License,
  6. * version 2, as published by the Free Software Foundation.
  7. *
  8. * This program is distributed in the hope it will be useful, but WITHOUT
  9. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  10. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  11. * more details.
  12. *
  13. * You should have received a copy of the GNU General Public License along with
  14. * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
  15. * Place - Suite 330, Boston, MA 02111-1307 USA.
  16. *
  17. * Author: Lucy Liu <lucy.liu@intel.com>
  18. */
  19. #include <linux/netdevice.h>
  20. #include <linux/netlink.h>
  21. #include <net/netlink.h>
  22. #include <net/rtnetlink.h>
  23. #include <linux/dcbnl.h>
  24. #include <linux/rtnetlink.h>
  25. #include <net/sock.h>
  26. /**
  27. * Data Center Bridging (DCB) is a collection of Ethernet enhancements
  28. * intended to allow network traffic with differing requirements
  29. * (highly reliable, no drops vs. best effort vs. low latency) to operate
  30. * and co-exist on Ethernet. Current DCB features are:
  31. *
  32. * Enhanced Transmission Selection (aka Priority Grouping [PG]) - provides a
  33. * framework for assigning bandwidth guarantees to traffic classes.
  34. *
  35. * Priority-based Flow Control (PFC) - provides a flow control mechanism which
  36. * can work independently for each 802.1p priority.
  37. *
  38. * Congestion Notification - provides a mechanism for end-to-end congestion
  39. * control for protocols which do not have built-in congestion management.
  40. *
  41. * More information about the emerging standards for these Ethernet features
  42. * can be found at: http://www.ieee802.org/1/pages/dcbridges.html
  43. *
  44. * This file implements an rtnetlink interface to allow configuration of DCB
  45. * features for capable devices.
  46. */
  47. MODULE_AUTHOR("Lucy Liu, <lucy.liu@intel.com>");
  48. MODULE_DESCRIPTION("Data Center Bridging generic netlink interface");
  49. MODULE_LICENSE("GPL");
  50. /**************** DCB attribute policies *************************************/
  51. /* DCB netlink attributes policy */
  52. static struct nla_policy dcbnl_rtnl_policy[DCB_ATTR_MAX + 1] = {
  53. [DCB_ATTR_IFNAME] = {.type = NLA_STRING, .len = IFNAMSIZ - 1},
  54. [DCB_ATTR_STATE] = {.type = NLA_U8},
  55. [DCB_ATTR_PFC_CFG] = {.type = NLA_NESTED},
  56. [DCB_ATTR_PG_CFG] = {.type = NLA_NESTED},
  57. [DCB_ATTR_SET_ALL] = {.type = NLA_U8},
  58. [DCB_ATTR_PERM_HWADDR] = {.type = NLA_FLAG},
  59. [DCB_ATTR_CAP] = {.type = NLA_NESTED},
  60. };
  61. /* DCB priority flow control to User Priority nested attributes */
  62. static struct nla_policy dcbnl_pfc_up_nest[DCB_PFC_UP_ATTR_MAX + 1] = {
  63. [DCB_PFC_UP_ATTR_0] = {.type = NLA_U8},
  64. [DCB_PFC_UP_ATTR_1] = {.type = NLA_U8},
  65. [DCB_PFC_UP_ATTR_2] = {.type = NLA_U8},
  66. [DCB_PFC_UP_ATTR_3] = {.type = NLA_U8},
  67. [DCB_PFC_UP_ATTR_4] = {.type = NLA_U8},
  68. [DCB_PFC_UP_ATTR_5] = {.type = NLA_U8},
  69. [DCB_PFC_UP_ATTR_6] = {.type = NLA_U8},
  70. [DCB_PFC_UP_ATTR_7] = {.type = NLA_U8},
  71. [DCB_PFC_UP_ATTR_ALL] = {.type = NLA_FLAG},
  72. };
  73. /* DCB priority grouping nested attributes */
  74. static struct nla_policy dcbnl_pg_nest[DCB_PG_ATTR_MAX + 1] = {
  75. [DCB_PG_ATTR_TC_0] = {.type = NLA_NESTED},
  76. [DCB_PG_ATTR_TC_1] = {.type = NLA_NESTED},
  77. [DCB_PG_ATTR_TC_2] = {.type = NLA_NESTED},
  78. [DCB_PG_ATTR_TC_3] = {.type = NLA_NESTED},
  79. [DCB_PG_ATTR_TC_4] = {.type = NLA_NESTED},
  80. [DCB_PG_ATTR_TC_5] = {.type = NLA_NESTED},
  81. [DCB_PG_ATTR_TC_6] = {.type = NLA_NESTED},
  82. [DCB_PG_ATTR_TC_7] = {.type = NLA_NESTED},
  83. [DCB_PG_ATTR_TC_ALL] = {.type = NLA_NESTED},
  84. [DCB_PG_ATTR_BW_ID_0] = {.type = NLA_U8},
  85. [DCB_PG_ATTR_BW_ID_1] = {.type = NLA_U8},
  86. [DCB_PG_ATTR_BW_ID_2] = {.type = NLA_U8},
  87. [DCB_PG_ATTR_BW_ID_3] = {.type = NLA_U8},
  88. [DCB_PG_ATTR_BW_ID_4] = {.type = NLA_U8},
  89. [DCB_PG_ATTR_BW_ID_5] = {.type = NLA_U8},
  90. [DCB_PG_ATTR_BW_ID_6] = {.type = NLA_U8},
  91. [DCB_PG_ATTR_BW_ID_7] = {.type = NLA_U8},
  92. [DCB_PG_ATTR_BW_ID_ALL] = {.type = NLA_FLAG},
  93. };
  94. /* DCB traffic class nested attributes. */
  95. static struct nla_policy dcbnl_tc_param_nest[DCB_TC_ATTR_PARAM_MAX + 1] = {
  96. [DCB_TC_ATTR_PARAM_PGID] = {.type = NLA_U8},
  97. [DCB_TC_ATTR_PARAM_UP_MAPPING] = {.type = NLA_U8},
  98. [DCB_TC_ATTR_PARAM_STRICT_PRIO] = {.type = NLA_U8},
  99. [DCB_TC_ATTR_PARAM_BW_PCT] = {.type = NLA_U8},
  100. [DCB_TC_ATTR_PARAM_ALL] = {.type = NLA_FLAG},
  101. };
  102. /* DCB capabilities nested attributes. */
  103. static struct nla_policy dcbnl_cap_nest[DCB_CAP_ATTR_MAX + 1] = {
  104. [DCB_CAP_ATTR_ALL] = {.type = NLA_FLAG},
  105. [DCB_CAP_ATTR_PG] = {.type = NLA_U8},
  106. [DCB_CAP_ATTR_PFC] = {.type = NLA_U8},
  107. [DCB_CAP_ATTR_UP2TC] = {.type = NLA_U8},
  108. [DCB_CAP_ATTR_PG_TCS] = {.type = NLA_U8},
  109. [DCB_CAP_ATTR_PFC_TCS] = {.type = NLA_U8},
  110. [DCB_CAP_ATTR_GSP] = {.type = NLA_U8},
  111. [DCB_CAP_ATTR_BCN] = {.type = NLA_U8},
  112. };
  113. /* standard netlink reply call */
  114. static int dcbnl_reply(u8 value, u8 event, u8 cmd, u8 attr, u32 pid,
  115. u32 seq, u16 flags)
  116. {
  117. struct sk_buff *dcbnl_skb;
  118. struct dcbmsg *dcb;
  119. struct nlmsghdr *nlh;
  120. int ret = -EINVAL;
  121. dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
  122. if (!dcbnl_skb)
  123. return ret;
  124. nlh = NLMSG_NEW(dcbnl_skb, pid, seq, event, sizeof(*dcb), flags);
  125. dcb = NLMSG_DATA(nlh);
  126. dcb->dcb_family = AF_UNSPEC;
  127. dcb->cmd = cmd;
  128. dcb->dcb_pad = 0;
  129. ret = nla_put_u8(dcbnl_skb, attr, value);
  130. if (ret)
  131. goto err;
  132. /* end the message, assign the nlmsg_len. */
  133. nlmsg_end(dcbnl_skb, nlh);
  134. ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
  135. if (ret)
  136. goto err;
  137. return 0;
  138. nlmsg_failure:
  139. err:
  140. kfree(dcbnl_skb);
  141. return ret;
  142. }
  143. static int dcbnl_getstate(struct net_device *netdev, struct nlattr **tb,
  144. u32 pid, u32 seq, u16 flags)
  145. {
  146. int ret = -EINVAL;
  147. /* if (!tb[DCB_ATTR_STATE] || !netdev->dcbnl_ops->getstate) */
  148. if (!netdev->dcbnl_ops->getstate)
  149. return ret;
  150. ret = dcbnl_reply(netdev->dcbnl_ops->getstate(netdev), RTM_GETDCB,
  151. DCB_CMD_GSTATE, DCB_ATTR_STATE, pid, seq, flags);
  152. return ret;
  153. }
  154. static int dcbnl_getpfccfg(struct net_device *netdev, struct nlattr **tb,
  155. u32 pid, u32 seq, u16 flags)
  156. {
  157. struct sk_buff *dcbnl_skb;
  158. struct nlmsghdr *nlh;
  159. struct dcbmsg *dcb;
  160. struct nlattr *data[DCB_PFC_UP_ATTR_MAX + 1], *nest;
  161. u8 value;
  162. int ret = -EINVAL;
  163. int i;
  164. int getall = 0;
  165. if (!tb[DCB_ATTR_PFC_CFG] || !netdev->dcbnl_ops->getpfccfg)
  166. return ret;
  167. ret = nla_parse_nested(data, DCB_PFC_UP_ATTR_MAX,
  168. tb[DCB_ATTR_PFC_CFG],
  169. dcbnl_pfc_up_nest);
  170. if (ret)
  171. goto err_out;
  172. dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
  173. if (!dcbnl_skb)
  174. goto err_out;
  175. nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
  176. dcb = NLMSG_DATA(nlh);
  177. dcb->dcb_family = AF_UNSPEC;
  178. dcb->cmd = DCB_CMD_PFC_GCFG;
  179. nest = nla_nest_start(dcbnl_skb, DCB_ATTR_PFC_CFG);
  180. if (!nest)
  181. goto err;
  182. if (data[DCB_PFC_UP_ATTR_ALL])
  183. getall = 1;
  184. for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) {
  185. if (!getall && !data[i])
  186. continue;
  187. netdev->dcbnl_ops->getpfccfg(netdev, i - DCB_PFC_UP_ATTR_0,
  188. &value);
  189. ret = nla_put_u8(dcbnl_skb, i, value);
  190. if (ret) {
  191. nla_nest_cancel(dcbnl_skb, nest);
  192. goto err;
  193. }
  194. }
  195. nla_nest_end(dcbnl_skb, nest);
  196. nlmsg_end(dcbnl_skb, nlh);
  197. ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
  198. if (ret)
  199. goto err;
  200. return 0;
  201. nlmsg_failure:
  202. err:
  203. kfree(dcbnl_skb);
  204. err_out:
  205. return -EINVAL;
  206. }
  207. static int dcbnl_getperm_hwaddr(struct net_device *netdev, struct nlattr **tb,
  208. u32 pid, u32 seq, u16 flags)
  209. {
  210. struct sk_buff *dcbnl_skb;
  211. struct nlmsghdr *nlh;
  212. struct dcbmsg *dcb;
  213. u8 perm_addr[MAX_ADDR_LEN];
  214. int ret = -EINVAL;
  215. if (!netdev->dcbnl_ops->getpermhwaddr)
  216. return ret;
  217. dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
  218. if (!dcbnl_skb)
  219. goto err_out;
  220. nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
  221. dcb = NLMSG_DATA(nlh);
  222. dcb->dcb_family = AF_UNSPEC;
  223. dcb->cmd = DCB_CMD_GPERM_HWADDR;
  224. netdev->dcbnl_ops->getpermhwaddr(netdev, perm_addr);
  225. ret = nla_put(dcbnl_skb, DCB_ATTR_PERM_HWADDR, sizeof(perm_addr),
  226. perm_addr);
  227. nlmsg_end(dcbnl_skb, nlh);
  228. ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
  229. if (ret)
  230. goto err;
  231. return 0;
  232. nlmsg_failure:
  233. err:
  234. kfree(dcbnl_skb);
  235. err_out:
  236. return -EINVAL;
  237. }
  238. static int dcbnl_getcap(struct net_device *netdev, struct nlattr **tb,
  239. u32 pid, u32 seq, u16 flags)
  240. {
  241. struct sk_buff *dcbnl_skb;
  242. struct nlmsghdr *nlh;
  243. struct dcbmsg *dcb;
  244. struct nlattr *data[DCB_CAP_ATTR_MAX + 1], *nest;
  245. u8 value;
  246. int ret = -EINVAL;
  247. int i;
  248. int getall = 0;
  249. if (!tb[DCB_ATTR_CAP] || !netdev->dcbnl_ops->getcap)
  250. return ret;
  251. ret = nla_parse_nested(data, DCB_CAP_ATTR_MAX, tb[DCB_ATTR_CAP],
  252. dcbnl_cap_nest);
  253. if (ret)
  254. goto err_out;
  255. dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
  256. if (!dcbnl_skb)
  257. goto err_out;
  258. nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
  259. dcb = NLMSG_DATA(nlh);
  260. dcb->dcb_family = AF_UNSPEC;
  261. dcb->cmd = DCB_CMD_GCAP;
  262. nest = nla_nest_start(dcbnl_skb, DCB_ATTR_CAP);
  263. if (!nest)
  264. goto err;
  265. if (data[DCB_CAP_ATTR_ALL])
  266. getall = 1;
  267. for (i = DCB_CAP_ATTR_ALL+1; i <= DCB_CAP_ATTR_MAX; i++) {
  268. if (!getall && !data[i])
  269. continue;
  270. if (!netdev->dcbnl_ops->getcap(netdev, i, &value)) {
  271. ret = nla_put_u8(dcbnl_skb, i, value);
  272. if (ret) {
  273. nla_nest_cancel(dcbnl_skb, nest);
  274. goto err;
  275. }
  276. }
  277. }
  278. nla_nest_end(dcbnl_skb, nest);
  279. nlmsg_end(dcbnl_skb, nlh);
  280. ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
  281. if (ret)
  282. goto err;
  283. return 0;
  284. nlmsg_failure:
  285. err:
  286. kfree(dcbnl_skb);
  287. err_out:
  288. return -EINVAL;
  289. }
  290. static int __dcbnl_pg_getcfg(struct net_device *netdev, struct nlattr **tb,
  291. u32 pid, u32 seq, u16 flags, int dir)
  292. {
  293. struct sk_buff *dcbnl_skb;
  294. struct nlmsghdr *nlh;
  295. struct dcbmsg *dcb;
  296. struct nlattr *pg_nest, *param_nest, *data;
  297. struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1];
  298. struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1];
  299. u8 prio, pgid, tc_pct, up_map;
  300. int ret = -EINVAL;
  301. int getall = 0;
  302. int i;
  303. if (!tb[DCB_ATTR_PG_CFG] ||
  304. !netdev->dcbnl_ops->getpgtccfgtx ||
  305. !netdev->dcbnl_ops->getpgtccfgrx ||
  306. !netdev->dcbnl_ops->getpgbwgcfgtx ||
  307. !netdev->dcbnl_ops->getpgbwgcfgrx)
  308. return ret;
  309. ret = nla_parse_nested(pg_tb, DCB_PG_ATTR_MAX,
  310. tb[DCB_ATTR_PG_CFG], dcbnl_pg_nest);
  311. if (ret)
  312. goto err_out;
  313. dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
  314. if (!dcbnl_skb)
  315. goto err_out;
  316. nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
  317. dcb = NLMSG_DATA(nlh);
  318. dcb->dcb_family = AF_UNSPEC;
  319. dcb->cmd = (dir) ? DCB_CMD_PGRX_GCFG : DCB_CMD_PGTX_GCFG;
  320. pg_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_PG_CFG);
  321. if (!pg_nest)
  322. goto err;
  323. if (pg_tb[DCB_PG_ATTR_TC_ALL])
  324. getall = 1;
  325. for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) {
  326. if (!getall && !pg_tb[i])
  327. continue;
  328. if (pg_tb[DCB_PG_ATTR_TC_ALL])
  329. data = pg_tb[DCB_PG_ATTR_TC_ALL];
  330. else
  331. data = pg_tb[i];
  332. ret = nla_parse_nested(param_tb, DCB_TC_ATTR_PARAM_MAX,
  333. data, dcbnl_tc_param_nest);
  334. if (ret)
  335. goto err_pg;
  336. param_nest = nla_nest_start(dcbnl_skb, i);
  337. if (!param_nest)
  338. goto err_pg;
  339. pgid = DCB_ATTR_VALUE_UNDEFINED;
  340. prio = DCB_ATTR_VALUE_UNDEFINED;
  341. tc_pct = DCB_ATTR_VALUE_UNDEFINED;
  342. up_map = DCB_ATTR_VALUE_UNDEFINED;
  343. if (dir) {
  344. /* Rx */
  345. netdev->dcbnl_ops->getpgtccfgrx(netdev,
  346. i - DCB_PG_ATTR_TC_0, &prio,
  347. &pgid, &tc_pct, &up_map);
  348. } else {
  349. /* Tx */
  350. netdev->dcbnl_ops->getpgtccfgtx(netdev,
  351. i - DCB_PG_ATTR_TC_0, &prio,
  352. &pgid, &tc_pct, &up_map);
  353. }
  354. if (param_tb[DCB_TC_ATTR_PARAM_PGID] ||
  355. param_tb[DCB_TC_ATTR_PARAM_ALL]) {
  356. ret = nla_put_u8(dcbnl_skb,
  357. DCB_TC_ATTR_PARAM_PGID, pgid);
  358. if (ret)
  359. goto err_param;
  360. }
  361. if (param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING] ||
  362. param_tb[DCB_TC_ATTR_PARAM_ALL]) {
  363. ret = nla_put_u8(dcbnl_skb,
  364. DCB_TC_ATTR_PARAM_UP_MAPPING, up_map);
  365. if (ret)
  366. goto err_param;
  367. }
  368. if (param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO] ||
  369. param_tb[DCB_TC_ATTR_PARAM_ALL]) {
  370. ret = nla_put_u8(dcbnl_skb,
  371. DCB_TC_ATTR_PARAM_STRICT_PRIO, prio);
  372. if (ret)
  373. goto err_param;
  374. }
  375. if (param_tb[DCB_TC_ATTR_PARAM_BW_PCT] ||
  376. param_tb[DCB_TC_ATTR_PARAM_ALL]) {
  377. ret = nla_put_u8(dcbnl_skb, DCB_TC_ATTR_PARAM_BW_PCT,
  378. tc_pct);
  379. if (ret)
  380. goto err_param;
  381. }
  382. nla_nest_end(dcbnl_skb, param_nest);
  383. }
  384. if (pg_tb[DCB_PG_ATTR_BW_ID_ALL])
  385. getall = 1;
  386. else
  387. getall = 0;
  388. for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) {
  389. if (!getall && !pg_tb[i])
  390. continue;
  391. tc_pct = DCB_ATTR_VALUE_UNDEFINED;
  392. if (dir) {
  393. /* Rx */
  394. netdev->dcbnl_ops->getpgbwgcfgrx(netdev,
  395. i - DCB_PG_ATTR_BW_ID_0, &tc_pct);
  396. } else {
  397. /* Tx */
  398. netdev->dcbnl_ops->getpgbwgcfgtx(netdev,
  399. i - DCB_PG_ATTR_BW_ID_0, &tc_pct);
  400. }
  401. ret = nla_put_u8(dcbnl_skb, i, tc_pct);
  402. if (ret)
  403. goto err_pg;
  404. }
  405. nla_nest_end(dcbnl_skb, pg_nest);
  406. nlmsg_end(dcbnl_skb, nlh);
  407. ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
  408. if (ret)
  409. goto err;
  410. return 0;
  411. err_param:
  412. nla_nest_cancel(dcbnl_skb, param_nest);
  413. err_pg:
  414. nla_nest_cancel(dcbnl_skb, pg_nest);
  415. nlmsg_failure:
  416. err:
  417. kfree(dcbnl_skb);
  418. err_out:
  419. ret = -EINVAL;
  420. return ret;
  421. }
  422. static int dcbnl_pgtx_getcfg(struct net_device *netdev, struct nlattr **tb,
  423. u32 pid, u32 seq, u16 flags)
  424. {
  425. return __dcbnl_pg_getcfg(netdev, tb, pid, seq, flags, 0);
  426. }
  427. static int dcbnl_pgrx_getcfg(struct net_device *netdev, struct nlattr **tb,
  428. u32 pid, u32 seq, u16 flags)
  429. {
  430. return __dcbnl_pg_getcfg(netdev, tb, pid, seq, flags, 1);
  431. }
  432. static int dcbnl_setstate(struct net_device *netdev, struct nlattr **tb,
  433. u32 pid, u32 seq, u16 flags)
  434. {
  435. int ret = -EINVAL;
  436. u8 value;
  437. if (!tb[DCB_ATTR_STATE] || !netdev->dcbnl_ops->setstate)
  438. return ret;
  439. value = nla_get_u8(tb[DCB_ATTR_STATE]);
  440. netdev->dcbnl_ops->setstate(netdev, value);
  441. ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_SSTATE, DCB_ATTR_STATE,
  442. pid, seq, flags);
  443. return ret;
  444. }
  445. static int dcbnl_setpfccfg(struct net_device *netdev, struct nlattr **tb,
  446. u32 pid, u32 seq, u16 flags)
  447. {
  448. struct nlattr *data[DCB_PFC_UP_ATTR_MAX + 1];
  449. int i;
  450. int ret = -EINVAL;
  451. u8 value;
  452. if (!tb[DCB_ATTR_PFC_CFG] || !netdev->dcbnl_ops->setpfccfg)
  453. return ret;
  454. ret = nla_parse_nested(data, DCB_PFC_UP_ATTR_MAX,
  455. tb[DCB_ATTR_PFC_CFG],
  456. dcbnl_pfc_up_nest);
  457. if (ret)
  458. goto err;
  459. for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) {
  460. if (data[i] == NULL)
  461. continue;
  462. value = nla_get_u8(data[i]);
  463. netdev->dcbnl_ops->setpfccfg(netdev,
  464. data[i]->nla_type - DCB_PFC_UP_ATTR_0, value);
  465. }
  466. ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_PFC_SCFG, DCB_ATTR_PFC_CFG,
  467. pid, seq, flags);
  468. err:
  469. return ret;
  470. }
  471. static int dcbnl_setall(struct net_device *netdev, struct nlattr **tb,
  472. u32 pid, u32 seq, u16 flags)
  473. {
  474. int ret = -EINVAL;
  475. if (!tb[DCB_ATTR_SET_ALL] || !netdev->dcbnl_ops->setall)
  476. return ret;
  477. ret = dcbnl_reply(netdev->dcbnl_ops->setall(netdev), RTM_SETDCB,
  478. DCB_CMD_SET_ALL, DCB_ATTR_SET_ALL, pid, seq, flags);
  479. return ret;
  480. }
  481. static int __dcbnl_pg_setcfg(struct net_device *netdev, struct nlattr **tb,
  482. u32 pid, u32 seq, u16 flags, int dir)
  483. {
  484. struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1];
  485. struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1];
  486. int ret = -EINVAL;
  487. int i;
  488. u8 pgid;
  489. u8 up_map;
  490. u8 prio;
  491. u8 tc_pct;
  492. if (!tb[DCB_ATTR_PG_CFG] ||
  493. !netdev->dcbnl_ops->setpgtccfgtx ||
  494. !netdev->dcbnl_ops->setpgtccfgrx ||
  495. !netdev->dcbnl_ops->setpgbwgcfgtx ||
  496. !netdev->dcbnl_ops->setpgbwgcfgrx)
  497. return ret;
  498. ret = nla_parse_nested(pg_tb, DCB_PG_ATTR_MAX,
  499. tb[DCB_ATTR_PG_CFG], dcbnl_pg_nest);
  500. if (ret)
  501. goto err;
  502. for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) {
  503. if (!pg_tb[i])
  504. continue;
  505. ret = nla_parse_nested(param_tb, DCB_TC_ATTR_PARAM_MAX,
  506. pg_tb[i], dcbnl_tc_param_nest);
  507. if (ret)
  508. goto err;
  509. pgid = DCB_ATTR_VALUE_UNDEFINED;
  510. prio = DCB_ATTR_VALUE_UNDEFINED;
  511. tc_pct = DCB_ATTR_VALUE_UNDEFINED;
  512. up_map = DCB_ATTR_VALUE_UNDEFINED;
  513. if (param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO])
  514. prio =
  515. nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO]);
  516. if (param_tb[DCB_TC_ATTR_PARAM_PGID])
  517. pgid = nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_PGID]);
  518. if (param_tb[DCB_TC_ATTR_PARAM_BW_PCT])
  519. tc_pct = nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_BW_PCT]);
  520. if (param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING])
  521. up_map =
  522. nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING]);
  523. /* dir: Tx = 0, Rx = 1 */
  524. if (dir) {
  525. /* Rx */
  526. netdev->dcbnl_ops->setpgtccfgrx(netdev,
  527. i - DCB_PG_ATTR_TC_0,
  528. prio, pgid, tc_pct, up_map);
  529. } else {
  530. /* Tx */
  531. netdev->dcbnl_ops->setpgtccfgtx(netdev,
  532. i - DCB_PG_ATTR_TC_0,
  533. prio, pgid, tc_pct, up_map);
  534. }
  535. }
  536. for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) {
  537. if (!pg_tb[i])
  538. continue;
  539. tc_pct = nla_get_u8(pg_tb[i]);
  540. /* dir: Tx = 0, Rx = 1 */
  541. if (dir) {
  542. /* Rx */
  543. netdev->dcbnl_ops->setpgbwgcfgrx(netdev,
  544. i - DCB_PG_ATTR_BW_ID_0, tc_pct);
  545. } else {
  546. /* Tx */
  547. netdev->dcbnl_ops->setpgbwgcfgtx(netdev,
  548. i - DCB_PG_ATTR_BW_ID_0, tc_pct);
  549. }
  550. }
  551. ret = dcbnl_reply(0, RTM_SETDCB,
  552. (dir ? DCB_CMD_PGRX_SCFG : DCB_CMD_PGTX_SCFG),
  553. DCB_ATTR_PG_CFG, pid, seq, flags);
  554. err:
  555. return ret;
  556. }
  557. static int dcbnl_pgtx_setcfg(struct net_device *netdev, struct nlattr **tb,
  558. u32 pid, u32 seq, u16 flags)
  559. {
  560. return __dcbnl_pg_setcfg(netdev, tb, pid, seq, flags, 0);
  561. }
  562. static int dcbnl_pgrx_setcfg(struct net_device *netdev, struct nlattr **tb,
  563. u32 pid, u32 seq, u16 flags)
  564. {
  565. return __dcbnl_pg_setcfg(netdev, tb, pid, seq, flags, 1);
  566. }
  567. static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
  568. {
  569. struct net *net = sock_net(skb->sk);
  570. struct net_device *netdev;
  571. struct dcbmsg *dcb = (struct dcbmsg *)NLMSG_DATA(nlh);
  572. struct nlattr *tb[DCB_ATTR_MAX + 1];
  573. u32 pid = skb ? NETLINK_CB(skb).pid : 0;
  574. int ret = -EINVAL;
  575. if (net != &init_net)
  576. return -EINVAL;
  577. ret = nlmsg_parse(nlh, sizeof(*dcb), tb, DCB_ATTR_MAX,
  578. dcbnl_rtnl_policy);
  579. if (ret < 0)
  580. return ret;
  581. if (!tb[DCB_ATTR_IFNAME])
  582. return -EINVAL;
  583. netdev = dev_get_by_name(&init_net, nla_data(tb[DCB_ATTR_IFNAME]));
  584. if (!netdev)
  585. return -EINVAL;
  586. if (!netdev->dcbnl_ops)
  587. goto errout;
  588. switch (dcb->cmd) {
  589. case DCB_CMD_GSTATE:
  590. ret = dcbnl_getstate(netdev, tb, pid, nlh->nlmsg_seq,
  591. nlh->nlmsg_flags);
  592. goto out;
  593. case DCB_CMD_PFC_GCFG:
  594. ret = dcbnl_getpfccfg(netdev, tb, pid, nlh->nlmsg_seq,
  595. nlh->nlmsg_flags);
  596. goto out;
  597. case DCB_CMD_GPERM_HWADDR:
  598. ret = dcbnl_getperm_hwaddr(netdev, tb, pid, nlh->nlmsg_seq,
  599. nlh->nlmsg_flags);
  600. goto out;
  601. case DCB_CMD_PGTX_GCFG:
  602. ret = dcbnl_pgtx_getcfg(netdev, tb, pid, nlh->nlmsg_seq,
  603. nlh->nlmsg_flags);
  604. goto out;
  605. case DCB_CMD_PGRX_GCFG:
  606. ret = dcbnl_pgrx_getcfg(netdev, tb, pid, nlh->nlmsg_seq,
  607. nlh->nlmsg_flags);
  608. goto out;
  609. case DCB_CMD_SSTATE:
  610. ret = dcbnl_setstate(netdev, tb, pid, nlh->nlmsg_seq,
  611. nlh->nlmsg_flags);
  612. goto out;
  613. case DCB_CMD_PFC_SCFG:
  614. ret = dcbnl_setpfccfg(netdev, tb, pid, nlh->nlmsg_seq,
  615. nlh->nlmsg_flags);
  616. goto out;
  617. case DCB_CMD_SET_ALL:
  618. ret = dcbnl_setall(netdev, tb, pid, nlh->nlmsg_seq,
  619. nlh->nlmsg_flags);
  620. goto out;
  621. case DCB_CMD_PGTX_SCFG:
  622. ret = dcbnl_pgtx_setcfg(netdev, tb, pid, nlh->nlmsg_seq,
  623. nlh->nlmsg_flags);
  624. goto out;
  625. case DCB_CMD_PGRX_SCFG:
  626. ret = dcbnl_pgrx_setcfg(netdev, tb, pid, nlh->nlmsg_seq,
  627. nlh->nlmsg_flags);
  628. goto out;
  629. case DCB_CMD_GCAP:
  630. ret = dcbnl_getcap(netdev, tb, pid, nlh->nlmsg_seq,
  631. nlh->nlmsg_flags);
  632. goto out;
  633. default:
  634. goto errout;
  635. }
  636. errout:
  637. ret = -EINVAL;
  638. out:
  639. dev_put(netdev);
  640. return ret;
  641. }
  642. static int __init dcbnl_init(void)
  643. {
  644. rtnl_register(PF_UNSPEC, RTM_GETDCB, dcb_doit, NULL);
  645. rtnl_register(PF_UNSPEC, RTM_SETDCB, dcb_doit, NULL);
  646. return 0;
  647. }
  648. module_init(dcbnl_init);
  649. static void __exit dcbnl_exit(void)
  650. {
  651. rtnl_unregister(PF_UNSPEC, RTM_GETDCB);
  652. rtnl_unregister(PF_UNSPEC, RTM_SETDCB);
  653. }
  654. module_exit(dcbnl_exit);