dcbnl.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704
  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. };
  60. /* DCB priority flow control to User Priority nested attributes */
  61. static struct nla_policy dcbnl_pfc_up_nest[DCB_PFC_UP_ATTR_MAX + 1] = {
  62. [DCB_PFC_UP_ATTR_0] = {.type = NLA_U8},
  63. [DCB_PFC_UP_ATTR_1] = {.type = NLA_U8},
  64. [DCB_PFC_UP_ATTR_2] = {.type = NLA_U8},
  65. [DCB_PFC_UP_ATTR_3] = {.type = NLA_U8},
  66. [DCB_PFC_UP_ATTR_4] = {.type = NLA_U8},
  67. [DCB_PFC_UP_ATTR_5] = {.type = NLA_U8},
  68. [DCB_PFC_UP_ATTR_6] = {.type = NLA_U8},
  69. [DCB_PFC_UP_ATTR_7] = {.type = NLA_U8},
  70. [DCB_PFC_UP_ATTR_ALL] = {.type = NLA_FLAG},
  71. };
  72. /* DCB priority grouping nested attributes */
  73. static struct nla_policy dcbnl_pg_nest[DCB_PG_ATTR_MAX + 1] = {
  74. [DCB_PG_ATTR_TC_0] = {.type = NLA_NESTED},
  75. [DCB_PG_ATTR_TC_1] = {.type = NLA_NESTED},
  76. [DCB_PG_ATTR_TC_2] = {.type = NLA_NESTED},
  77. [DCB_PG_ATTR_TC_3] = {.type = NLA_NESTED},
  78. [DCB_PG_ATTR_TC_4] = {.type = NLA_NESTED},
  79. [DCB_PG_ATTR_TC_5] = {.type = NLA_NESTED},
  80. [DCB_PG_ATTR_TC_6] = {.type = NLA_NESTED},
  81. [DCB_PG_ATTR_TC_7] = {.type = NLA_NESTED},
  82. [DCB_PG_ATTR_TC_ALL] = {.type = NLA_NESTED},
  83. [DCB_PG_ATTR_BW_ID_0] = {.type = NLA_U8},
  84. [DCB_PG_ATTR_BW_ID_1] = {.type = NLA_U8},
  85. [DCB_PG_ATTR_BW_ID_2] = {.type = NLA_U8},
  86. [DCB_PG_ATTR_BW_ID_3] = {.type = NLA_U8},
  87. [DCB_PG_ATTR_BW_ID_4] = {.type = NLA_U8},
  88. [DCB_PG_ATTR_BW_ID_5] = {.type = NLA_U8},
  89. [DCB_PG_ATTR_BW_ID_6] = {.type = NLA_U8},
  90. [DCB_PG_ATTR_BW_ID_7] = {.type = NLA_U8},
  91. [DCB_PG_ATTR_BW_ID_ALL] = {.type = NLA_FLAG},
  92. };
  93. /* DCB traffic class nested attributes. */
  94. static struct nla_policy dcbnl_tc_param_nest[DCB_TC_ATTR_PARAM_MAX + 1] = {
  95. [DCB_TC_ATTR_PARAM_PGID] = {.type = NLA_U8},
  96. [DCB_TC_ATTR_PARAM_UP_MAPPING] = {.type = NLA_U8},
  97. [DCB_TC_ATTR_PARAM_STRICT_PRIO] = {.type = NLA_U8},
  98. [DCB_TC_ATTR_PARAM_BW_PCT] = {.type = NLA_U8},
  99. [DCB_TC_ATTR_PARAM_ALL] = {.type = NLA_FLAG},
  100. };
  101. /* standard netlink reply call */
  102. static int dcbnl_reply(u8 value, u8 event, u8 cmd, u8 attr, u32 pid,
  103. u32 seq, u16 flags)
  104. {
  105. struct sk_buff *dcbnl_skb;
  106. struct dcbmsg *dcb;
  107. struct nlmsghdr *nlh;
  108. int ret = -EINVAL;
  109. dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
  110. if (!dcbnl_skb)
  111. return ret;
  112. nlh = NLMSG_NEW(dcbnl_skb, pid, seq, event, sizeof(*dcb), flags);
  113. dcb = NLMSG_DATA(nlh);
  114. dcb->dcb_family = AF_UNSPEC;
  115. dcb->cmd = cmd;
  116. dcb->dcb_pad = 0;
  117. ret = nla_put_u8(dcbnl_skb, attr, value);
  118. if (ret)
  119. goto err;
  120. /* end the message, assign the nlmsg_len. */
  121. nlmsg_end(dcbnl_skb, nlh);
  122. ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
  123. if (ret)
  124. goto err;
  125. return 0;
  126. nlmsg_failure:
  127. err:
  128. kfree(dcbnl_skb);
  129. return ret;
  130. }
  131. static int dcbnl_getstate(struct net_device *netdev, struct nlattr **tb,
  132. u32 pid, u32 seq, u16 flags)
  133. {
  134. int ret = -EINVAL;
  135. /* if (!tb[DCB_ATTR_STATE] || !netdev->dcbnl_ops->getstate) */
  136. if (!netdev->dcbnl_ops->getstate)
  137. return ret;
  138. ret = dcbnl_reply(netdev->dcbnl_ops->getstate(netdev), RTM_GETDCB,
  139. DCB_CMD_GSTATE, DCB_ATTR_STATE, pid, seq, flags);
  140. return ret;
  141. }
  142. static int dcbnl_getpfccfg(struct net_device *netdev, struct nlattr **tb,
  143. u32 pid, u32 seq, u16 flags)
  144. {
  145. struct sk_buff *dcbnl_skb;
  146. struct nlmsghdr *nlh;
  147. struct dcbmsg *dcb;
  148. struct nlattr *data[DCB_PFC_UP_ATTR_MAX + 1], *nest;
  149. u8 value;
  150. int ret = -EINVAL;
  151. int i;
  152. int getall = 0;
  153. if (!tb[DCB_ATTR_PFC_CFG] || !netdev->dcbnl_ops->getpfccfg)
  154. return ret;
  155. ret = nla_parse_nested(data, DCB_PFC_UP_ATTR_MAX,
  156. tb[DCB_ATTR_PFC_CFG],
  157. dcbnl_pfc_up_nest);
  158. if (ret)
  159. goto err_out;
  160. dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
  161. if (!dcbnl_skb)
  162. goto err_out;
  163. nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
  164. dcb = NLMSG_DATA(nlh);
  165. dcb->dcb_family = AF_UNSPEC;
  166. dcb->cmd = DCB_CMD_PFC_GCFG;
  167. nest = nla_nest_start(dcbnl_skb, DCB_ATTR_PFC_CFG);
  168. if (!nest)
  169. goto err;
  170. if (data[DCB_PFC_UP_ATTR_ALL])
  171. getall = 1;
  172. for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) {
  173. if (!getall && !data[i])
  174. continue;
  175. netdev->dcbnl_ops->getpfccfg(netdev, i - DCB_PFC_UP_ATTR_0,
  176. &value);
  177. ret = nla_put_u8(dcbnl_skb, i, value);
  178. if (ret) {
  179. nla_nest_cancel(dcbnl_skb, nest);
  180. goto err;
  181. }
  182. }
  183. nla_nest_end(dcbnl_skb, nest);
  184. nlmsg_end(dcbnl_skb, nlh);
  185. ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
  186. if (ret)
  187. goto err;
  188. return 0;
  189. nlmsg_failure:
  190. err:
  191. kfree(dcbnl_skb);
  192. err_out:
  193. return -EINVAL;
  194. }
  195. static int dcbnl_getperm_hwaddr(struct net_device *netdev, struct nlattr **tb,
  196. u32 pid, u32 seq, u16 flags)
  197. {
  198. struct sk_buff *dcbnl_skb;
  199. struct nlmsghdr *nlh;
  200. struct dcbmsg *dcb;
  201. u8 perm_addr[MAX_ADDR_LEN];
  202. int ret = -EINVAL;
  203. if (!netdev->dcbnl_ops->getpermhwaddr)
  204. return ret;
  205. dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
  206. if (!dcbnl_skb)
  207. goto err_out;
  208. nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
  209. dcb = NLMSG_DATA(nlh);
  210. dcb->dcb_family = AF_UNSPEC;
  211. dcb->cmd = DCB_CMD_GPERM_HWADDR;
  212. netdev->dcbnl_ops->getpermhwaddr(netdev, perm_addr);
  213. ret = nla_put(dcbnl_skb, DCB_ATTR_PERM_HWADDR, sizeof(perm_addr),
  214. perm_addr);
  215. nlmsg_end(dcbnl_skb, nlh);
  216. ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
  217. if (ret)
  218. goto err;
  219. return 0;
  220. nlmsg_failure:
  221. err:
  222. kfree(dcbnl_skb);
  223. err_out:
  224. return -EINVAL;
  225. }
  226. static int __dcbnl_pg_getcfg(struct net_device *netdev, struct nlattr **tb,
  227. u32 pid, u32 seq, u16 flags, int dir)
  228. {
  229. struct sk_buff *dcbnl_skb;
  230. struct nlmsghdr *nlh;
  231. struct dcbmsg *dcb;
  232. struct nlattr *pg_nest, *param_nest, *data;
  233. struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1];
  234. struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1];
  235. u8 prio, pgid, tc_pct, up_map;
  236. int ret = -EINVAL;
  237. int getall = 0;
  238. int i;
  239. if (!tb[DCB_ATTR_PG_CFG] ||
  240. !netdev->dcbnl_ops->getpgtccfgtx ||
  241. !netdev->dcbnl_ops->getpgtccfgrx ||
  242. !netdev->dcbnl_ops->getpgbwgcfgtx ||
  243. !netdev->dcbnl_ops->getpgbwgcfgrx)
  244. return ret;
  245. ret = nla_parse_nested(pg_tb, DCB_PG_ATTR_MAX,
  246. tb[DCB_ATTR_PG_CFG], dcbnl_pg_nest);
  247. if (ret)
  248. goto err_out;
  249. dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
  250. if (!dcbnl_skb)
  251. goto err_out;
  252. nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
  253. dcb = NLMSG_DATA(nlh);
  254. dcb->dcb_family = AF_UNSPEC;
  255. dcb->cmd = (dir) ? DCB_CMD_PGRX_GCFG : DCB_CMD_PGTX_GCFG;
  256. pg_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_PG_CFG);
  257. if (!pg_nest)
  258. goto err;
  259. if (pg_tb[DCB_PG_ATTR_TC_ALL])
  260. getall = 1;
  261. for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) {
  262. if (!getall && !pg_tb[i])
  263. continue;
  264. if (pg_tb[DCB_PG_ATTR_TC_ALL])
  265. data = pg_tb[DCB_PG_ATTR_TC_ALL];
  266. else
  267. data = pg_tb[i];
  268. ret = nla_parse_nested(param_tb, DCB_TC_ATTR_PARAM_MAX,
  269. data, dcbnl_tc_param_nest);
  270. if (ret)
  271. goto err_pg;
  272. param_nest = nla_nest_start(dcbnl_skb, i);
  273. if (!param_nest)
  274. goto err_pg;
  275. pgid = DCB_ATTR_VALUE_UNDEFINED;
  276. prio = DCB_ATTR_VALUE_UNDEFINED;
  277. tc_pct = DCB_ATTR_VALUE_UNDEFINED;
  278. up_map = DCB_ATTR_VALUE_UNDEFINED;
  279. if (dir) {
  280. /* Rx */
  281. netdev->dcbnl_ops->getpgtccfgrx(netdev,
  282. i - DCB_PG_ATTR_TC_0, &prio,
  283. &pgid, &tc_pct, &up_map);
  284. } else {
  285. /* Tx */
  286. netdev->dcbnl_ops->getpgtccfgtx(netdev,
  287. i - DCB_PG_ATTR_TC_0, &prio,
  288. &pgid, &tc_pct, &up_map);
  289. }
  290. if (param_tb[DCB_TC_ATTR_PARAM_PGID] ||
  291. param_tb[DCB_TC_ATTR_PARAM_ALL]) {
  292. ret = nla_put_u8(dcbnl_skb,
  293. DCB_TC_ATTR_PARAM_PGID, pgid);
  294. if (ret)
  295. goto err_param;
  296. }
  297. if (param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING] ||
  298. param_tb[DCB_TC_ATTR_PARAM_ALL]) {
  299. ret = nla_put_u8(dcbnl_skb,
  300. DCB_TC_ATTR_PARAM_UP_MAPPING, up_map);
  301. if (ret)
  302. goto err_param;
  303. }
  304. if (param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO] ||
  305. param_tb[DCB_TC_ATTR_PARAM_ALL]) {
  306. ret = nla_put_u8(dcbnl_skb,
  307. DCB_TC_ATTR_PARAM_STRICT_PRIO, prio);
  308. if (ret)
  309. goto err_param;
  310. }
  311. if (param_tb[DCB_TC_ATTR_PARAM_BW_PCT] ||
  312. param_tb[DCB_TC_ATTR_PARAM_ALL]) {
  313. ret = nla_put_u8(dcbnl_skb, DCB_TC_ATTR_PARAM_BW_PCT,
  314. tc_pct);
  315. if (ret)
  316. goto err_param;
  317. }
  318. nla_nest_end(dcbnl_skb, param_nest);
  319. }
  320. if (pg_tb[DCB_PG_ATTR_BW_ID_ALL])
  321. getall = 1;
  322. else
  323. getall = 0;
  324. for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) {
  325. if (!getall && !pg_tb[i])
  326. continue;
  327. tc_pct = DCB_ATTR_VALUE_UNDEFINED;
  328. if (dir) {
  329. /* Rx */
  330. netdev->dcbnl_ops->getpgbwgcfgrx(netdev,
  331. i - DCB_PG_ATTR_BW_ID_0, &tc_pct);
  332. } else {
  333. /* Tx */
  334. netdev->dcbnl_ops->getpgbwgcfgtx(netdev,
  335. i - DCB_PG_ATTR_BW_ID_0, &tc_pct);
  336. }
  337. ret = nla_put_u8(dcbnl_skb, i, tc_pct);
  338. if (ret)
  339. goto err_pg;
  340. }
  341. nla_nest_end(dcbnl_skb, pg_nest);
  342. nlmsg_end(dcbnl_skb, nlh);
  343. ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
  344. if (ret)
  345. goto err;
  346. return 0;
  347. err_param:
  348. nla_nest_cancel(dcbnl_skb, param_nest);
  349. err_pg:
  350. nla_nest_cancel(dcbnl_skb, pg_nest);
  351. nlmsg_failure:
  352. err:
  353. kfree(dcbnl_skb);
  354. err_out:
  355. ret = -EINVAL;
  356. return ret;
  357. }
  358. static int dcbnl_pgtx_getcfg(struct net_device *netdev, struct nlattr **tb,
  359. u32 pid, u32 seq, u16 flags)
  360. {
  361. return __dcbnl_pg_getcfg(netdev, tb, pid, seq, flags, 0);
  362. }
  363. static int dcbnl_pgrx_getcfg(struct net_device *netdev, struct nlattr **tb,
  364. u32 pid, u32 seq, u16 flags)
  365. {
  366. return __dcbnl_pg_getcfg(netdev, tb, pid, seq, flags, 1);
  367. }
  368. static int dcbnl_setstate(struct net_device *netdev, struct nlattr **tb,
  369. u32 pid, u32 seq, u16 flags)
  370. {
  371. int ret = -EINVAL;
  372. u8 value;
  373. if (!tb[DCB_ATTR_STATE] || !netdev->dcbnl_ops->setstate)
  374. return ret;
  375. value = nla_get_u8(tb[DCB_ATTR_STATE]);
  376. netdev->dcbnl_ops->setstate(netdev, value);
  377. ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_SSTATE, DCB_ATTR_STATE,
  378. pid, seq, flags);
  379. return ret;
  380. }
  381. static int dcbnl_setpfccfg(struct net_device *netdev, struct nlattr **tb,
  382. u32 pid, u32 seq, u16 flags)
  383. {
  384. struct nlattr *data[DCB_PFC_UP_ATTR_MAX + 1];
  385. int i;
  386. int ret = -EINVAL;
  387. u8 value;
  388. if (!tb[DCB_ATTR_PFC_CFG] || !netdev->dcbnl_ops->setpfccfg)
  389. return ret;
  390. ret = nla_parse_nested(data, DCB_PFC_UP_ATTR_MAX,
  391. tb[DCB_ATTR_PFC_CFG],
  392. dcbnl_pfc_up_nest);
  393. if (ret)
  394. goto err;
  395. for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) {
  396. if (data[i] == NULL)
  397. continue;
  398. value = nla_get_u8(data[i]);
  399. netdev->dcbnl_ops->setpfccfg(netdev,
  400. data[i]->nla_type - DCB_PFC_UP_ATTR_0, value);
  401. }
  402. ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_PFC_SCFG, DCB_ATTR_PFC_CFG,
  403. pid, seq, flags);
  404. err:
  405. return ret;
  406. }
  407. static int dcbnl_setall(struct net_device *netdev, struct nlattr **tb,
  408. u32 pid, u32 seq, u16 flags)
  409. {
  410. int ret = -EINVAL;
  411. if (!tb[DCB_ATTR_SET_ALL] || !netdev->dcbnl_ops->setall)
  412. return ret;
  413. ret = dcbnl_reply(netdev->dcbnl_ops->setall(netdev), RTM_SETDCB,
  414. DCB_CMD_SET_ALL, DCB_ATTR_SET_ALL, pid, seq, flags);
  415. return ret;
  416. }
  417. static int __dcbnl_pg_setcfg(struct net_device *netdev, struct nlattr **tb,
  418. u32 pid, u32 seq, u16 flags, int dir)
  419. {
  420. struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1];
  421. struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1];
  422. int ret = -EINVAL;
  423. int i;
  424. u8 pgid;
  425. u8 up_map;
  426. u8 prio;
  427. u8 tc_pct;
  428. if (!tb[DCB_ATTR_PG_CFG] ||
  429. !netdev->dcbnl_ops->setpgtccfgtx ||
  430. !netdev->dcbnl_ops->setpgtccfgrx ||
  431. !netdev->dcbnl_ops->setpgbwgcfgtx ||
  432. !netdev->dcbnl_ops->setpgbwgcfgrx)
  433. return ret;
  434. ret = nla_parse_nested(pg_tb, DCB_PG_ATTR_MAX,
  435. tb[DCB_ATTR_PG_CFG], dcbnl_pg_nest);
  436. if (ret)
  437. goto err;
  438. for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) {
  439. if (!pg_tb[i])
  440. continue;
  441. ret = nla_parse_nested(param_tb, DCB_TC_ATTR_PARAM_MAX,
  442. pg_tb[i], dcbnl_tc_param_nest);
  443. if (ret)
  444. goto err;
  445. pgid = DCB_ATTR_VALUE_UNDEFINED;
  446. prio = DCB_ATTR_VALUE_UNDEFINED;
  447. tc_pct = DCB_ATTR_VALUE_UNDEFINED;
  448. up_map = DCB_ATTR_VALUE_UNDEFINED;
  449. if (param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO])
  450. prio =
  451. nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO]);
  452. if (param_tb[DCB_TC_ATTR_PARAM_PGID])
  453. pgid = nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_PGID]);
  454. if (param_tb[DCB_TC_ATTR_PARAM_BW_PCT])
  455. tc_pct = nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_BW_PCT]);
  456. if (param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING])
  457. up_map =
  458. nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING]);
  459. /* dir: Tx = 0, Rx = 1 */
  460. if (dir) {
  461. /* Rx */
  462. netdev->dcbnl_ops->setpgtccfgrx(netdev,
  463. i - DCB_PG_ATTR_TC_0,
  464. prio, pgid, tc_pct, up_map);
  465. } else {
  466. /* Tx */
  467. netdev->dcbnl_ops->setpgtccfgtx(netdev,
  468. i - DCB_PG_ATTR_TC_0,
  469. prio, pgid, tc_pct, up_map);
  470. }
  471. }
  472. for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) {
  473. if (!pg_tb[i])
  474. continue;
  475. tc_pct = nla_get_u8(pg_tb[i]);
  476. /* dir: Tx = 0, Rx = 1 */
  477. if (dir) {
  478. /* Rx */
  479. netdev->dcbnl_ops->setpgbwgcfgrx(netdev,
  480. i - DCB_PG_ATTR_BW_ID_0, tc_pct);
  481. } else {
  482. /* Tx */
  483. netdev->dcbnl_ops->setpgbwgcfgtx(netdev,
  484. i - DCB_PG_ATTR_BW_ID_0, tc_pct);
  485. }
  486. }
  487. ret = dcbnl_reply(0, RTM_SETDCB,
  488. (dir ? DCB_CMD_PGRX_SCFG : DCB_CMD_PGTX_SCFG),
  489. DCB_ATTR_PG_CFG, pid, seq, flags);
  490. err:
  491. return ret;
  492. }
  493. static int dcbnl_pgtx_setcfg(struct net_device *netdev, struct nlattr **tb,
  494. u32 pid, u32 seq, u16 flags)
  495. {
  496. return __dcbnl_pg_setcfg(netdev, tb, pid, seq, flags, 0);
  497. }
  498. static int dcbnl_pgrx_setcfg(struct net_device *netdev, struct nlattr **tb,
  499. u32 pid, u32 seq, u16 flags)
  500. {
  501. return __dcbnl_pg_setcfg(netdev, tb, pid, seq, flags, 1);
  502. }
  503. static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
  504. {
  505. struct net *net = sock_net(skb->sk);
  506. struct net_device *netdev;
  507. struct dcbmsg *dcb = (struct dcbmsg *)NLMSG_DATA(nlh);
  508. struct nlattr *tb[DCB_ATTR_MAX + 1];
  509. u32 pid = skb ? NETLINK_CB(skb).pid : 0;
  510. int ret = -EINVAL;
  511. if (net != &init_net)
  512. return -EINVAL;
  513. ret = nlmsg_parse(nlh, sizeof(*dcb), tb, DCB_ATTR_MAX,
  514. dcbnl_rtnl_policy);
  515. if (ret < 0)
  516. return ret;
  517. if (!tb[DCB_ATTR_IFNAME])
  518. return -EINVAL;
  519. netdev = dev_get_by_name(&init_net, nla_data(tb[DCB_ATTR_IFNAME]));
  520. if (!netdev)
  521. return -EINVAL;
  522. if (!netdev->dcbnl_ops)
  523. goto errout;
  524. switch (dcb->cmd) {
  525. case DCB_CMD_GSTATE:
  526. ret = dcbnl_getstate(netdev, tb, pid, nlh->nlmsg_seq,
  527. nlh->nlmsg_flags);
  528. goto out;
  529. case DCB_CMD_PFC_GCFG:
  530. ret = dcbnl_getpfccfg(netdev, tb, pid, nlh->nlmsg_seq,
  531. nlh->nlmsg_flags);
  532. goto out;
  533. case DCB_CMD_GPERM_HWADDR:
  534. ret = dcbnl_getperm_hwaddr(netdev, tb, pid, nlh->nlmsg_seq,
  535. nlh->nlmsg_flags);
  536. goto out;
  537. case DCB_CMD_PGTX_GCFG:
  538. ret = dcbnl_pgtx_getcfg(netdev, tb, pid, nlh->nlmsg_seq,
  539. nlh->nlmsg_flags);
  540. goto out;
  541. case DCB_CMD_PGRX_GCFG:
  542. ret = dcbnl_pgrx_getcfg(netdev, tb, pid, nlh->nlmsg_seq,
  543. nlh->nlmsg_flags);
  544. goto out;
  545. case DCB_CMD_SSTATE:
  546. ret = dcbnl_setstate(netdev, tb, pid, nlh->nlmsg_seq,
  547. nlh->nlmsg_flags);
  548. goto out;
  549. case DCB_CMD_PFC_SCFG:
  550. ret = dcbnl_setpfccfg(netdev, tb, pid, nlh->nlmsg_seq,
  551. nlh->nlmsg_flags);
  552. goto out;
  553. case DCB_CMD_SET_ALL:
  554. ret = dcbnl_setall(netdev, tb, pid, nlh->nlmsg_seq,
  555. nlh->nlmsg_flags);
  556. goto out;
  557. case DCB_CMD_PGTX_SCFG:
  558. ret = dcbnl_pgtx_setcfg(netdev, tb, pid, nlh->nlmsg_seq,
  559. nlh->nlmsg_flags);
  560. goto out;
  561. case DCB_CMD_PGRX_SCFG:
  562. ret = dcbnl_pgrx_setcfg(netdev, tb, pid, nlh->nlmsg_seq,
  563. nlh->nlmsg_flags);
  564. goto out;
  565. default:
  566. goto errout;
  567. }
  568. errout:
  569. ret = -EINVAL;
  570. out:
  571. dev_put(netdev);
  572. return ret;
  573. }
  574. static int __init dcbnl_init(void)
  575. {
  576. rtnl_register(PF_UNSPEC, RTM_GETDCB, dcb_doit, NULL);
  577. rtnl_register(PF_UNSPEC, RTM_SETDCB, dcb_doit, NULL);
  578. return 0;
  579. }
  580. module_init(dcbnl_init);
  581. static void __exit dcbnl_exit(void)
  582. {
  583. rtnl_unregister(PF_UNSPEC, RTM_GETDCB);
  584. rtnl_unregister(PF_UNSPEC, RTM_SETDCB);
  585. }
  586. module_exit(dcbnl_exit);