dcbnl.c 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251
  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 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_NUL_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. [DCB_ATTR_PFC_STATE] = {.type = NLA_U8},
  61. [DCB_ATTR_BCN] = {.type = NLA_NESTED},
  62. [DCB_ATTR_APP] = {.type = NLA_NESTED},
  63. };
  64. /* DCB priority flow control to User Priority nested attributes */
  65. static struct nla_policy dcbnl_pfc_up_nest[DCB_PFC_UP_ATTR_MAX + 1] = {
  66. [DCB_PFC_UP_ATTR_0] = {.type = NLA_U8},
  67. [DCB_PFC_UP_ATTR_1] = {.type = NLA_U8},
  68. [DCB_PFC_UP_ATTR_2] = {.type = NLA_U8},
  69. [DCB_PFC_UP_ATTR_3] = {.type = NLA_U8},
  70. [DCB_PFC_UP_ATTR_4] = {.type = NLA_U8},
  71. [DCB_PFC_UP_ATTR_5] = {.type = NLA_U8},
  72. [DCB_PFC_UP_ATTR_6] = {.type = NLA_U8},
  73. [DCB_PFC_UP_ATTR_7] = {.type = NLA_U8},
  74. [DCB_PFC_UP_ATTR_ALL] = {.type = NLA_FLAG},
  75. };
  76. /* DCB priority grouping nested attributes */
  77. static struct nla_policy dcbnl_pg_nest[DCB_PG_ATTR_MAX + 1] = {
  78. [DCB_PG_ATTR_TC_0] = {.type = NLA_NESTED},
  79. [DCB_PG_ATTR_TC_1] = {.type = NLA_NESTED},
  80. [DCB_PG_ATTR_TC_2] = {.type = NLA_NESTED},
  81. [DCB_PG_ATTR_TC_3] = {.type = NLA_NESTED},
  82. [DCB_PG_ATTR_TC_4] = {.type = NLA_NESTED},
  83. [DCB_PG_ATTR_TC_5] = {.type = NLA_NESTED},
  84. [DCB_PG_ATTR_TC_6] = {.type = NLA_NESTED},
  85. [DCB_PG_ATTR_TC_7] = {.type = NLA_NESTED},
  86. [DCB_PG_ATTR_TC_ALL] = {.type = NLA_NESTED},
  87. [DCB_PG_ATTR_BW_ID_0] = {.type = NLA_U8},
  88. [DCB_PG_ATTR_BW_ID_1] = {.type = NLA_U8},
  89. [DCB_PG_ATTR_BW_ID_2] = {.type = NLA_U8},
  90. [DCB_PG_ATTR_BW_ID_3] = {.type = NLA_U8},
  91. [DCB_PG_ATTR_BW_ID_4] = {.type = NLA_U8},
  92. [DCB_PG_ATTR_BW_ID_5] = {.type = NLA_U8},
  93. [DCB_PG_ATTR_BW_ID_6] = {.type = NLA_U8},
  94. [DCB_PG_ATTR_BW_ID_7] = {.type = NLA_U8},
  95. [DCB_PG_ATTR_BW_ID_ALL] = {.type = NLA_FLAG},
  96. };
  97. /* DCB traffic class nested attributes. */
  98. static struct nla_policy dcbnl_tc_param_nest[DCB_TC_ATTR_PARAM_MAX + 1] = {
  99. [DCB_TC_ATTR_PARAM_PGID] = {.type = NLA_U8},
  100. [DCB_TC_ATTR_PARAM_UP_MAPPING] = {.type = NLA_U8},
  101. [DCB_TC_ATTR_PARAM_STRICT_PRIO] = {.type = NLA_U8},
  102. [DCB_TC_ATTR_PARAM_BW_PCT] = {.type = NLA_U8},
  103. [DCB_TC_ATTR_PARAM_ALL] = {.type = NLA_FLAG},
  104. };
  105. /* DCB capabilities nested attributes. */
  106. static struct nla_policy dcbnl_cap_nest[DCB_CAP_ATTR_MAX + 1] = {
  107. [DCB_CAP_ATTR_ALL] = {.type = NLA_FLAG},
  108. [DCB_CAP_ATTR_PG] = {.type = NLA_U8},
  109. [DCB_CAP_ATTR_PFC] = {.type = NLA_U8},
  110. [DCB_CAP_ATTR_UP2TC] = {.type = NLA_U8},
  111. [DCB_CAP_ATTR_PG_TCS] = {.type = NLA_U8},
  112. [DCB_CAP_ATTR_PFC_TCS] = {.type = NLA_U8},
  113. [DCB_CAP_ATTR_GSP] = {.type = NLA_U8},
  114. [DCB_CAP_ATTR_BCN] = {.type = NLA_U8},
  115. };
  116. /* DCB capabilities nested attributes. */
  117. static struct nla_policy dcbnl_numtcs_nest[DCB_NUMTCS_ATTR_MAX + 1] = {
  118. [DCB_NUMTCS_ATTR_ALL] = {.type = NLA_FLAG},
  119. [DCB_NUMTCS_ATTR_PG] = {.type = NLA_U8},
  120. [DCB_NUMTCS_ATTR_PFC] = {.type = NLA_U8},
  121. };
  122. /* DCB BCN nested attributes. */
  123. static struct nla_policy dcbnl_bcn_nest[DCB_BCN_ATTR_MAX + 1] = {
  124. [DCB_BCN_ATTR_RP_0] = {.type = NLA_U8},
  125. [DCB_BCN_ATTR_RP_1] = {.type = NLA_U8},
  126. [DCB_BCN_ATTR_RP_2] = {.type = NLA_U8},
  127. [DCB_BCN_ATTR_RP_3] = {.type = NLA_U8},
  128. [DCB_BCN_ATTR_RP_4] = {.type = NLA_U8},
  129. [DCB_BCN_ATTR_RP_5] = {.type = NLA_U8},
  130. [DCB_BCN_ATTR_RP_6] = {.type = NLA_U8},
  131. [DCB_BCN_ATTR_RP_7] = {.type = NLA_U8},
  132. [DCB_BCN_ATTR_RP_ALL] = {.type = NLA_FLAG},
  133. [DCB_BCN_ATTR_BCNA_0] = {.type = NLA_U32},
  134. [DCB_BCN_ATTR_BCNA_1] = {.type = NLA_U32},
  135. [DCB_BCN_ATTR_ALPHA] = {.type = NLA_U32},
  136. [DCB_BCN_ATTR_BETA] = {.type = NLA_U32},
  137. [DCB_BCN_ATTR_GD] = {.type = NLA_U32},
  138. [DCB_BCN_ATTR_GI] = {.type = NLA_U32},
  139. [DCB_BCN_ATTR_TMAX] = {.type = NLA_U32},
  140. [DCB_BCN_ATTR_TD] = {.type = NLA_U32},
  141. [DCB_BCN_ATTR_RMIN] = {.type = NLA_U32},
  142. [DCB_BCN_ATTR_W] = {.type = NLA_U32},
  143. [DCB_BCN_ATTR_RD] = {.type = NLA_U32},
  144. [DCB_BCN_ATTR_RU] = {.type = NLA_U32},
  145. [DCB_BCN_ATTR_WRTT] = {.type = NLA_U32},
  146. [DCB_BCN_ATTR_RI] = {.type = NLA_U32},
  147. [DCB_BCN_ATTR_C] = {.type = NLA_U32},
  148. [DCB_BCN_ATTR_ALL] = {.type = NLA_FLAG},
  149. };
  150. /* DCB APP nested attributes. */
  151. static struct nla_policy dcbnl_app_nest[DCB_APP_ATTR_MAX + 1] = {
  152. [DCB_APP_ATTR_IDTYPE] = {.type = NLA_U8},
  153. [DCB_APP_ATTR_ID] = {.type = NLA_U16},
  154. [DCB_APP_ATTR_PRIORITY] = {.type = NLA_U8},
  155. };
  156. /* standard netlink reply call */
  157. static int dcbnl_reply(u8 value, u8 event, u8 cmd, u8 attr, u32 pid,
  158. u32 seq, u16 flags)
  159. {
  160. struct sk_buff *dcbnl_skb;
  161. struct dcbmsg *dcb;
  162. struct nlmsghdr *nlh;
  163. int ret = -EINVAL;
  164. dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
  165. if (!dcbnl_skb)
  166. return ret;
  167. nlh = NLMSG_NEW(dcbnl_skb, pid, seq, event, sizeof(*dcb), flags);
  168. dcb = NLMSG_DATA(nlh);
  169. dcb->dcb_family = AF_UNSPEC;
  170. dcb->cmd = cmd;
  171. dcb->dcb_pad = 0;
  172. ret = nla_put_u8(dcbnl_skb, attr, value);
  173. if (ret)
  174. goto err;
  175. /* end the message, assign the nlmsg_len. */
  176. nlmsg_end(dcbnl_skb, nlh);
  177. ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
  178. if (ret)
  179. return -EINVAL;
  180. return 0;
  181. nlmsg_failure:
  182. err:
  183. kfree_skb(dcbnl_skb);
  184. return ret;
  185. }
  186. static int dcbnl_getstate(struct net_device *netdev, struct nlattr **tb,
  187. u32 pid, u32 seq, u16 flags)
  188. {
  189. int ret = -EINVAL;
  190. /* if (!tb[DCB_ATTR_STATE] || !netdev->dcbnl_ops->getstate) */
  191. if (!netdev->dcbnl_ops->getstate)
  192. return ret;
  193. ret = dcbnl_reply(netdev->dcbnl_ops->getstate(netdev), RTM_GETDCB,
  194. DCB_CMD_GSTATE, DCB_ATTR_STATE, pid, seq, flags);
  195. return ret;
  196. }
  197. static int dcbnl_getpfccfg(struct net_device *netdev, struct nlattr **tb,
  198. u32 pid, u32 seq, u16 flags)
  199. {
  200. struct sk_buff *dcbnl_skb;
  201. struct nlmsghdr *nlh;
  202. struct dcbmsg *dcb;
  203. struct nlattr *data[DCB_PFC_UP_ATTR_MAX + 1], *nest;
  204. u8 value;
  205. int ret = -EINVAL;
  206. int i;
  207. int getall = 0;
  208. if (!tb[DCB_ATTR_PFC_CFG] || !netdev->dcbnl_ops->getpfccfg)
  209. return ret;
  210. ret = nla_parse_nested(data, DCB_PFC_UP_ATTR_MAX,
  211. tb[DCB_ATTR_PFC_CFG],
  212. dcbnl_pfc_up_nest);
  213. if (ret)
  214. goto err_out;
  215. dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
  216. if (!dcbnl_skb)
  217. goto err_out;
  218. nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
  219. dcb = NLMSG_DATA(nlh);
  220. dcb->dcb_family = AF_UNSPEC;
  221. dcb->cmd = DCB_CMD_PFC_GCFG;
  222. nest = nla_nest_start(dcbnl_skb, DCB_ATTR_PFC_CFG);
  223. if (!nest)
  224. goto err;
  225. if (data[DCB_PFC_UP_ATTR_ALL])
  226. getall = 1;
  227. for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) {
  228. if (!getall && !data[i])
  229. continue;
  230. netdev->dcbnl_ops->getpfccfg(netdev, i - DCB_PFC_UP_ATTR_0,
  231. &value);
  232. ret = nla_put_u8(dcbnl_skb, i, value);
  233. if (ret) {
  234. nla_nest_cancel(dcbnl_skb, nest);
  235. goto err;
  236. }
  237. }
  238. nla_nest_end(dcbnl_skb, nest);
  239. nlmsg_end(dcbnl_skb, nlh);
  240. ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
  241. if (ret)
  242. goto err_out;
  243. return 0;
  244. nlmsg_failure:
  245. err:
  246. kfree_skb(dcbnl_skb);
  247. err_out:
  248. return -EINVAL;
  249. }
  250. static int dcbnl_getperm_hwaddr(struct net_device *netdev, struct nlattr **tb,
  251. u32 pid, u32 seq, u16 flags)
  252. {
  253. struct sk_buff *dcbnl_skb;
  254. struct nlmsghdr *nlh;
  255. struct dcbmsg *dcb;
  256. u8 perm_addr[MAX_ADDR_LEN];
  257. int ret = -EINVAL;
  258. if (!netdev->dcbnl_ops->getpermhwaddr)
  259. return ret;
  260. dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
  261. if (!dcbnl_skb)
  262. goto err_out;
  263. nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
  264. dcb = NLMSG_DATA(nlh);
  265. dcb->dcb_family = AF_UNSPEC;
  266. dcb->cmd = DCB_CMD_GPERM_HWADDR;
  267. netdev->dcbnl_ops->getpermhwaddr(netdev, perm_addr);
  268. ret = nla_put(dcbnl_skb, DCB_ATTR_PERM_HWADDR, sizeof(perm_addr),
  269. perm_addr);
  270. nlmsg_end(dcbnl_skb, nlh);
  271. ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
  272. if (ret)
  273. goto err_out;
  274. return 0;
  275. nlmsg_failure:
  276. kfree_skb(dcbnl_skb);
  277. err_out:
  278. return -EINVAL;
  279. }
  280. static int dcbnl_getcap(struct net_device *netdev, struct nlattr **tb,
  281. u32 pid, u32 seq, u16 flags)
  282. {
  283. struct sk_buff *dcbnl_skb;
  284. struct nlmsghdr *nlh;
  285. struct dcbmsg *dcb;
  286. struct nlattr *data[DCB_CAP_ATTR_MAX + 1], *nest;
  287. u8 value;
  288. int ret = -EINVAL;
  289. int i;
  290. int getall = 0;
  291. if (!tb[DCB_ATTR_CAP] || !netdev->dcbnl_ops->getcap)
  292. return ret;
  293. ret = nla_parse_nested(data, DCB_CAP_ATTR_MAX, tb[DCB_ATTR_CAP],
  294. dcbnl_cap_nest);
  295. if (ret)
  296. goto err_out;
  297. dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
  298. if (!dcbnl_skb)
  299. goto err_out;
  300. nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
  301. dcb = NLMSG_DATA(nlh);
  302. dcb->dcb_family = AF_UNSPEC;
  303. dcb->cmd = DCB_CMD_GCAP;
  304. nest = nla_nest_start(dcbnl_skb, DCB_ATTR_CAP);
  305. if (!nest)
  306. goto err;
  307. if (data[DCB_CAP_ATTR_ALL])
  308. getall = 1;
  309. for (i = DCB_CAP_ATTR_ALL+1; i <= DCB_CAP_ATTR_MAX; i++) {
  310. if (!getall && !data[i])
  311. continue;
  312. if (!netdev->dcbnl_ops->getcap(netdev, i, &value)) {
  313. ret = nla_put_u8(dcbnl_skb, i, value);
  314. if (ret) {
  315. nla_nest_cancel(dcbnl_skb, nest);
  316. goto err;
  317. }
  318. }
  319. }
  320. nla_nest_end(dcbnl_skb, nest);
  321. nlmsg_end(dcbnl_skb, nlh);
  322. ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
  323. if (ret)
  324. goto err_out;
  325. return 0;
  326. nlmsg_failure:
  327. err:
  328. kfree_skb(dcbnl_skb);
  329. err_out:
  330. return -EINVAL;
  331. }
  332. static int dcbnl_getnumtcs(struct net_device *netdev, struct nlattr **tb,
  333. u32 pid, u32 seq, u16 flags)
  334. {
  335. struct sk_buff *dcbnl_skb;
  336. struct nlmsghdr *nlh;
  337. struct dcbmsg *dcb;
  338. struct nlattr *data[DCB_NUMTCS_ATTR_MAX + 1], *nest;
  339. u8 value;
  340. int ret = -EINVAL;
  341. int i;
  342. int getall = 0;
  343. if (!tb[DCB_ATTR_NUMTCS] || !netdev->dcbnl_ops->getnumtcs)
  344. return ret;
  345. ret = nla_parse_nested(data, DCB_NUMTCS_ATTR_MAX, tb[DCB_ATTR_NUMTCS],
  346. dcbnl_numtcs_nest);
  347. if (ret) {
  348. ret = -EINVAL;
  349. goto err_out;
  350. }
  351. dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
  352. if (!dcbnl_skb) {
  353. ret = -EINVAL;
  354. goto err_out;
  355. }
  356. nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
  357. dcb = NLMSG_DATA(nlh);
  358. dcb->dcb_family = AF_UNSPEC;
  359. dcb->cmd = DCB_CMD_GNUMTCS;
  360. nest = nla_nest_start(dcbnl_skb, DCB_ATTR_NUMTCS);
  361. if (!nest) {
  362. ret = -EINVAL;
  363. goto err;
  364. }
  365. if (data[DCB_NUMTCS_ATTR_ALL])
  366. getall = 1;
  367. for (i = DCB_NUMTCS_ATTR_ALL+1; i <= DCB_NUMTCS_ATTR_MAX; i++) {
  368. if (!getall && !data[i])
  369. continue;
  370. ret = netdev->dcbnl_ops->getnumtcs(netdev, i, &value);
  371. if (!ret) {
  372. ret = nla_put_u8(dcbnl_skb, i, value);
  373. if (ret) {
  374. nla_nest_cancel(dcbnl_skb, nest);
  375. ret = -EINVAL;
  376. goto err;
  377. }
  378. } else {
  379. goto err;
  380. }
  381. }
  382. nla_nest_end(dcbnl_skb, nest);
  383. nlmsg_end(dcbnl_skb, nlh);
  384. ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
  385. if (ret) {
  386. ret = -EINVAL;
  387. goto err_out;
  388. }
  389. return 0;
  390. nlmsg_failure:
  391. err:
  392. kfree_skb(dcbnl_skb);
  393. err_out:
  394. return ret;
  395. }
  396. static int dcbnl_setnumtcs(struct net_device *netdev, struct nlattr **tb,
  397. u32 pid, u32 seq, u16 flags)
  398. {
  399. struct nlattr *data[DCB_NUMTCS_ATTR_MAX + 1];
  400. int ret = -EINVAL;
  401. u8 value;
  402. int i;
  403. if (!tb[DCB_ATTR_NUMTCS] || !netdev->dcbnl_ops->setnumtcs)
  404. return ret;
  405. ret = nla_parse_nested(data, DCB_NUMTCS_ATTR_MAX, tb[DCB_ATTR_NUMTCS],
  406. dcbnl_numtcs_nest);
  407. if (ret) {
  408. ret = -EINVAL;
  409. goto err;
  410. }
  411. for (i = DCB_NUMTCS_ATTR_ALL+1; i <= DCB_NUMTCS_ATTR_MAX; i++) {
  412. if (data[i] == NULL)
  413. continue;
  414. value = nla_get_u8(data[i]);
  415. ret = netdev->dcbnl_ops->setnumtcs(netdev, i, value);
  416. if (ret)
  417. goto operr;
  418. }
  419. operr:
  420. ret = dcbnl_reply(!!ret, RTM_SETDCB, DCB_CMD_SNUMTCS,
  421. DCB_ATTR_NUMTCS, pid, seq, flags);
  422. err:
  423. return ret;
  424. }
  425. static int dcbnl_getpfcstate(struct net_device *netdev, struct nlattr **tb,
  426. u32 pid, u32 seq, u16 flags)
  427. {
  428. int ret = -EINVAL;
  429. if (!netdev->dcbnl_ops->getpfcstate)
  430. return ret;
  431. ret = dcbnl_reply(netdev->dcbnl_ops->getpfcstate(netdev), RTM_GETDCB,
  432. DCB_CMD_PFC_GSTATE, DCB_ATTR_PFC_STATE,
  433. pid, seq, flags);
  434. return ret;
  435. }
  436. static int dcbnl_setpfcstate(struct net_device *netdev, struct nlattr **tb,
  437. u32 pid, u32 seq, u16 flags)
  438. {
  439. int ret = -EINVAL;
  440. u8 value;
  441. if (!tb[DCB_ATTR_PFC_STATE] || !netdev->dcbnl_ops->setpfcstate)
  442. return ret;
  443. value = nla_get_u8(tb[DCB_ATTR_PFC_STATE]);
  444. netdev->dcbnl_ops->setpfcstate(netdev, value);
  445. ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_PFC_SSTATE, DCB_ATTR_PFC_STATE,
  446. pid, seq, flags);
  447. return ret;
  448. }
  449. static int dcbnl_getapp(struct net_device *netdev, struct nlattr **tb,
  450. u32 pid, u32 seq, u16 flags)
  451. {
  452. struct sk_buff *dcbnl_skb;
  453. struct nlmsghdr *nlh;
  454. struct dcbmsg *dcb;
  455. struct nlattr *app_nest;
  456. struct nlattr *app_tb[DCB_APP_ATTR_MAX + 1];
  457. u16 id;
  458. u8 up, idtype;
  459. int ret = -EINVAL;
  460. if (!tb[DCB_ATTR_APP] || !netdev->dcbnl_ops->getapp)
  461. goto out;
  462. ret = nla_parse_nested(app_tb, DCB_APP_ATTR_MAX, tb[DCB_ATTR_APP],
  463. dcbnl_app_nest);
  464. if (ret)
  465. goto out;
  466. ret = -EINVAL;
  467. /* all must be non-null */
  468. if ((!app_tb[DCB_APP_ATTR_IDTYPE]) ||
  469. (!app_tb[DCB_APP_ATTR_ID]))
  470. goto out;
  471. /* either by eth type or by socket number */
  472. idtype = nla_get_u8(app_tb[DCB_APP_ATTR_IDTYPE]);
  473. if ((idtype != DCB_APP_IDTYPE_ETHTYPE) &&
  474. (idtype != DCB_APP_IDTYPE_PORTNUM))
  475. goto out;
  476. id = nla_get_u16(app_tb[DCB_APP_ATTR_ID]);
  477. up = netdev->dcbnl_ops->getapp(netdev, idtype, id);
  478. /* send this back */
  479. dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
  480. if (!dcbnl_skb)
  481. goto out;
  482. nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
  483. dcb = NLMSG_DATA(nlh);
  484. dcb->dcb_family = AF_UNSPEC;
  485. dcb->cmd = DCB_CMD_GAPP;
  486. app_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_APP);
  487. ret = nla_put_u8(dcbnl_skb, DCB_APP_ATTR_IDTYPE, idtype);
  488. if (ret)
  489. goto out_cancel;
  490. ret = nla_put_u16(dcbnl_skb, DCB_APP_ATTR_ID, id);
  491. if (ret)
  492. goto out_cancel;
  493. ret = nla_put_u8(dcbnl_skb, DCB_APP_ATTR_PRIORITY, up);
  494. if (ret)
  495. goto out_cancel;
  496. nla_nest_end(dcbnl_skb, app_nest);
  497. nlmsg_end(dcbnl_skb, nlh);
  498. ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
  499. if (ret)
  500. goto nlmsg_failure;
  501. goto out;
  502. out_cancel:
  503. nla_nest_cancel(dcbnl_skb, app_nest);
  504. nlmsg_failure:
  505. kfree_skb(dcbnl_skb);
  506. out:
  507. return ret;
  508. }
  509. static int dcbnl_setapp(struct net_device *netdev, struct nlattr **tb,
  510. u32 pid, u32 seq, u16 flags)
  511. {
  512. int ret = -EINVAL;
  513. u16 id;
  514. u8 up, idtype;
  515. struct nlattr *app_tb[DCB_APP_ATTR_MAX + 1];
  516. if (!tb[DCB_ATTR_APP] || !netdev->dcbnl_ops->setapp)
  517. goto out;
  518. ret = nla_parse_nested(app_tb, DCB_APP_ATTR_MAX, tb[DCB_ATTR_APP],
  519. dcbnl_app_nest);
  520. if (ret)
  521. goto out;
  522. ret = -EINVAL;
  523. /* all must be non-null */
  524. if ((!app_tb[DCB_APP_ATTR_IDTYPE]) ||
  525. (!app_tb[DCB_APP_ATTR_ID]) ||
  526. (!app_tb[DCB_APP_ATTR_PRIORITY]))
  527. goto out;
  528. /* either by eth type or by socket number */
  529. idtype = nla_get_u8(app_tb[DCB_APP_ATTR_IDTYPE]);
  530. if ((idtype != DCB_APP_IDTYPE_ETHTYPE) &&
  531. (idtype != DCB_APP_IDTYPE_PORTNUM))
  532. goto out;
  533. id = nla_get_u16(app_tb[DCB_APP_ATTR_ID]);
  534. up = nla_get_u8(app_tb[DCB_APP_ATTR_PRIORITY]);
  535. ret = dcbnl_reply(netdev->dcbnl_ops->setapp(netdev, idtype, id, up),
  536. RTM_SETDCB, DCB_CMD_SAPP, DCB_ATTR_APP,
  537. pid, seq, flags);
  538. out:
  539. return ret;
  540. }
  541. static int __dcbnl_pg_getcfg(struct net_device *netdev, struct nlattr **tb,
  542. u32 pid, u32 seq, u16 flags, int dir)
  543. {
  544. struct sk_buff *dcbnl_skb;
  545. struct nlmsghdr *nlh;
  546. struct dcbmsg *dcb;
  547. struct nlattr *pg_nest, *param_nest, *data;
  548. struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1];
  549. struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1];
  550. u8 prio, pgid, tc_pct, up_map;
  551. int ret = -EINVAL;
  552. int getall = 0;
  553. int i;
  554. if (!tb[DCB_ATTR_PG_CFG] ||
  555. !netdev->dcbnl_ops->getpgtccfgtx ||
  556. !netdev->dcbnl_ops->getpgtccfgrx ||
  557. !netdev->dcbnl_ops->getpgbwgcfgtx ||
  558. !netdev->dcbnl_ops->getpgbwgcfgrx)
  559. return ret;
  560. ret = nla_parse_nested(pg_tb, DCB_PG_ATTR_MAX,
  561. tb[DCB_ATTR_PG_CFG], dcbnl_pg_nest);
  562. if (ret)
  563. goto err_out;
  564. dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
  565. if (!dcbnl_skb)
  566. goto err_out;
  567. nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
  568. dcb = NLMSG_DATA(nlh);
  569. dcb->dcb_family = AF_UNSPEC;
  570. dcb->cmd = (dir) ? DCB_CMD_PGRX_GCFG : DCB_CMD_PGTX_GCFG;
  571. pg_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_PG_CFG);
  572. if (!pg_nest)
  573. goto err;
  574. if (pg_tb[DCB_PG_ATTR_TC_ALL])
  575. getall = 1;
  576. for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) {
  577. if (!getall && !pg_tb[i])
  578. continue;
  579. if (pg_tb[DCB_PG_ATTR_TC_ALL])
  580. data = pg_tb[DCB_PG_ATTR_TC_ALL];
  581. else
  582. data = pg_tb[i];
  583. ret = nla_parse_nested(param_tb, DCB_TC_ATTR_PARAM_MAX,
  584. data, dcbnl_tc_param_nest);
  585. if (ret)
  586. goto err_pg;
  587. param_nest = nla_nest_start(dcbnl_skb, i);
  588. if (!param_nest)
  589. goto err_pg;
  590. pgid = DCB_ATTR_VALUE_UNDEFINED;
  591. prio = DCB_ATTR_VALUE_UNDEFINED;
  592. tc_pct = DCB_ATTR_VALUE_UNDEFINED;
  593. up_map = DCB_ATTR_VALUE_UNDEFINED;
  594. if (dir) {
  595. /* Rx */
  596. netdev->dcbnl_ops->getpgtccfgrx(netdev,
  597. i - DCB_PG_ATTR_TC_0, &prio,
  598. &pgid, &tc_pct, &up_map);
  599. } else {
  600. /* Tx */
  601. netdev->dcbnl_ops->getpgtccfgtx(netdev,
  602. i - DCB_PG_ATTR_TC_0, &prio,
  603. &pgid, &tc_pct, &up_map);
  604. }
  605. if (param_tb[DCB_TC_ATTR_PARAM_PGID] ||
  606. param_tb[DCB_TC_ATTR_PARAM_ALL]) {
  607. ret = nla_put_u8(dcbnl_skb,
  608. DCB_TC_ATTR_PARAM_PGID, pgid);
  609. if (ret)
  610. goto err_param;
  611. }
  612. if (param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING] ||
  613. param_tb[DCB_TC_ATTR_PARAM_ALL]) {
  614. ret = nla_put_u8(dcbnl_skb,
  615. DCB_TC_ATTR_PARAM_UP_MAPPING, up_map);
  616. if (ret)
  617. goto err_param;
  618. }
  619. if (param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO] ||
  620. param_tb[DCB_TC_ATTR_PARAM_ALL]) {
  621. ret = nla_put_u8(dcbnl_skb,
  622. DCB_TC_ATTR_PARAM_STRICT_PRIO, prio);
  623. if (ret)
  624. goto err_param;
  625. }
  626. if (param_tb[DCB_TC_ATTR_PARAM_BW_PCT] ||
  627. param_tb[DCB_TC_ATTR_PARAM_ALL]) {
  628. ret = nla_put_u8(dcbnl_skb, DCB_TC_ATTR_PARAM_BW_PCT,
  629. tc_pct);
  630. if (ret)
  631. goto err_param;
  632. }
  633. nla_nest_end(dcbnl_skb, param_nest);
  634. }
  635. if (pg_tb[DCB_PG_ATTR_BW_ID_ALL])
  636. getall = 1;
  637. else
  638. getall = 0;
  639. for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) {
  640. if (!getall && !pg_tb[i])
  641. continue;
  642. tc_pct = DCB_ATTR_VALUE_UNDEFINED;
  643. if (dir) {
  644. /* Rx */
  645. netdev->dcbnl_ops->getpgbwgcfgrx(netdev,
  646. i - DCB_PG_ATTR_BW_ID_0, &tc_pct);
  647. } else {
  648. /* Tx */
  649. netdev->dcbnl_ops->getpgbwgcfgtx(netdev,
  650. i - DCB_PG_ATTR_BW_ID_0, &tc_pct);
  651. }
  652. ret = nla_put_u8(dcbnl_skb, i, tc_pct);
  653. if (ret)
  654. goto err_pg;
  655. }
  656. nla_nest_end(dcbnl_skb, pg_nest);
  657. nlmsg_end(dcbnl_skb, nlh);
  658. ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
  659. if (ret)
  660. goto err_out;
  661. return 0;
  662. err_param:
  663. nla_nest_cancel(dcbnl_skb, param_nest);
  664. err_pg:
  665. nla_nest_cancel(dcbnl_skb, pg_nest);
  666. nlmsg_failure:
  667. err:
  668. kfree_skb(dcbnl_skb);
  669. err_out:
  670. ret = -EINVAL;
  671. return ret;
  672. }
  673. static int dcbnl_pgtx_getcfg(struct net_device *netdev, struct nlattr **tb,
  674. u32 pid, u32 seq, u16 flags)
  675. {
  676. return __dcbnl_pg_getcfg(netdev, tb, pid, seq, flags, 0);
  677. }
  678. static int dcbnl_pgrx_getcfg(struct net_device *netdev, struct nlattr **tb,
  679. u32 pid, u32 seq, u16 flags)
  680. {
  681. return __dcbnl_pg_getcfg(netdev, tb, pid, seq, flags, 1);
  682. }
  683. static int dcbnl_setstate(struct net_device *netdev, struct nlattr **tb,
  684. u32 pid, u32 seq, u16 flags)
  685. {
  686. int ret = -EINVAL;
  687. u8 value;
  688. if (!tb[DCB_ATTR_STATE] || !netdev->dcbnl_ops->setstate)
  689. return ret;
  690. value = nla_get_u8(tb[DCB_ATTR_STATE]);
  691. ret = dcbnl_reply(netdev->dcbnl_ops->setstate(netdev, value),
  692. RTM_SETDCB, DCB_CMD_SSTATE, DCB_ATTR_STATE,
  693. pid, seq, flags);
  694. return ret;
  695. }
  696. static int dcbnl_setpfccfg(struct net_device *netdev, struct nlattr **tb,
  697. u32 pid, u32 seq, u16 flags)
  698. {
  699. struct nlattr *data[DCB_PFC_UP_ATTR_MAX + 1];
  700. int i;
  701. int ret = -EINVAL;
  702. u8 value;
  703. if (!tb[DCB_ATTR_PFC_CFG] || !netdev->dcbnl_ops->setpfccfg)
  704. return ret;
  705. ret = nla_parse_nested(data, DCB_PFC_UP_ATTR_MAX,
  706. tb[DCB_ATTR_PFC_CFG],
  707. dcbnl_pfc_up_nest);
  708. if (ret)
  709. goto err;
  710. for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) {
  711. if (data[i] == NULL)
  712. continue;
  713. value = nla_get_u8(data[i]);
  714. netdev->dcbnl_ops->setpfccfg(netdev,
  715. data[i]->nla_type - DCB_PFC_UP_ATTR_0, value);
  716. }
  717. ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_PFC_SCFG, DCB_ATTR_PFC_CFG,
  718. pid, seq, flags);
  719. err:
  720. return ret;
  721. }
  722. static int dcbnl_setall(struct net_device *netdev, struct nlattr **tb,
  723. u32 pid, u32 seq, u16 flags)
  724. {
  725. int ret = -EINVAL;
  726. if (!tb[DCB_ATTR_SET_ALL] || !netdev->dcbnl_ops->setall)
  727. return ret;
  728. ret = dcbnl_reply(netdev->dcbnl_ops->setall(netdev), RTM_SETDCB,
  729. DCB_CMD_SET_ALL, DCB_ATTR_SET_ALL, pid, seq, flags);
  730. return ret;
  731. }
  732. static int __dcbnl_pg_setcfg(struct net_device *netdev, struct nlattr **tb,
  733. u32 pid, u32 seq, u16 flags, int dir)
  734. {
  735. struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1];
  736. struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1];
  737. int ret = -EINVAL;
  738. int i;
  739. u8 pgid;
  740. u8 up_map;
  741. u8 prio;
  742. u8 tc_pct;
  743. if (!tb[DCB_ATTR_PG_CFG] ||
  744. !netdev->dcbnl_ops->setpgtccfgtx ||
  745. !netdev->dcbnl_ops->setpgtccfgrx ||
  746. !netdev->dcbnl_ops->setpgbwgcfgtx ||
  747. !netdev->dcbnl_ops->setpgbwgcfgrx)
  748. return ret;
  749. ret = nla_parse_nested(pg_tb, DCB_PG_ATTR_MAX,
  750. tb[DCB_ATTR_PG_CFG], dcbnl_pg_nest);
  751. if (ret)
  752. goto err;
  753. for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) {
  754. if (!pg_tb[i])
  755. continue;
  756. ret = nla_parse_nested(param_tb, DCB_TC_ATTR_PARAM_MAX,
  757. pg_tb[i], dcbnl_tc_param_nest);
  758. if (ret)
  759. goto err;
  760. pgid = DCB_ATTR_VALUE_UNDEFINED;
  761. prio = DCB_ATTR_VALUE_UNDEFINED;
  762. tc_pct = DCB_ATTR_VALUE_UNDEFINED;
  763. up_map = DCB_ATTR_VALUE_UNDEFINED;
  764. if (param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO])
  765. prio =
  766. nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO]);
  767. if (param_tb[DCB_TC_ATTR_PARAM_PGID])
  768. pgid = nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_PGID]);
  769. if (param_tb[DCB_TC_ATTR_PARAM_BW_PCT])
  770. tc_pct = nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_BW_PCT]);
  771. if (param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING])
  772. up_map =
  773. nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING]);
  774. /* dir: Tx = 0, Rx = 1 */
  775. if (dir) {
  776. /* Rx */
  777. netdev->dcbnl_ops->setpgtccfgrx(netdev,
  778. i - DCB_PG_ATTR_TC_0,
  779. prio, pgid, tc_pct, up_map);
  780. } else {
  781. /* Tx */
  782. netdev->dcbnl_ops->setpgtccfgtx(netdev,
  783. i - DCB_PG_ATTR_TC_0,
  784. prio, pgid, tc_pct, up_map);
  785. }
  786. }
  787. for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) {
  788. if (!pg_tb[i])
  789. continue;
  790. tc_pct = nla_get_u8(pg_tb[i]);
  791. /* dir: Tx = 0, Rx = 1 */
  792. if (dir) {
  793. /* Rx */
  794. netdev->dcbnl_ops->setpgbwgcfgrx(netdev,
  795. i - DCB_PG_ATTR_BW_ID_0, tc_pct);
  796. } else {
  797. /* Tx */
  798. netdev->dcbnl_ops->setpgbwgcfgtx(netdev,
  799. i - DCB_PG_ATTR_BW_ID_0, tc_pct);
  800. }
  801. }
  802. ret = dcbnl_reply(0, RTM_SETDCB,
  803. (dir ? DCB_CMD_PGRX_SCFG : DCB_CMD_PGTX_SCFG),
  804. DCB_ATTR_PG_CFG, pid, seq, flags);
  805. err:
  806. return ret;
  807. }
  808. static int dcbnl_pgtx_setcfg(struct net_device *netdev, struct nlattr **tb,
  809. u32 pid, u32 seq, u16 flags)
  810. {
  811. return __dcbnl_pg_setcfg(netdev, tb, pid, seq, flags, 0);
  812. }
  813. static int dcbnl_pgrx_setcfg(struct net_device *netdev, struct nlattr **tb,
  814. u32 pid, u32 seq, u16 flags)
  815. {
  816. return __dcbnl_pg_setcfg(netdev, tb, pid, seq, flags, 1);
  817. }
  818. static int dcbnl_bcn_getcfg(struct net_device *netdev, struct nlattr **tb,
  819. u32 pid, u32 seq, u16 flags)
  820. {
  821. struct sk_buff *dcbnl_skb;
  822. struct nlmsghdr *nlh;
  823. struct dcbmsg *dcb;
  824. struct nlattr *bcn_nest;
  825. struct nlattr *bcn_tb[DCB_BCN_ATTR_MAX + 1];
  826. u8 value_byte;
  827. u32 value_integer;
  828. int ret = -EINVAL;
  829. bool getall = false;
  830. int i;
  831. if (!tb[DCB_ATTR_BCN] || !netdev->dcbnl_ops->getbcnrp ||
  832. !netdev->dcbnl_ops->getbcncfg)
  833. return ret;
  834. ret = nla_parse_nested(bcn_tb, DCB_BCN_ATTR_MAX,
  835. tb[DCB_ATTR_BCN], dcbnl_bcn_nest);
  836. if (ret)
  837. goto err_out;
  838. dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
  839. if (!dcbnl_skb)
  840. goto err_out;
  841. nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
  842. dcb = NLMSG_DATA(nlh);
  843. dcb->dcb_family = AF_UNSPEC;
  844. dcb->cmd = DCB_CMD_BCN_GCFG;
  845. bcn_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_BCN);
  846. if (!bcn_nest)
  847. goto err;
  848. if (bcn_tb[DCB_BCN_ATTR_ALL])
  849. getall = true;
  850. for (i = DCB_BCN_ATTR_RP_0; i <= DCB_BCN_ATTR_RP_7; i++) {
  851. if (!getall && !bcn_tb[i])
  852. continue;
  853. netdev->dcbnl_ops->getbcnrp(netdev, i - DCB_BCN_ATTR_RP_0,
  854. &value_byte);
  855. ret = nla_put_u8(dcbnl_skb, i, value_byte);
  856. if (ret)
  857. goto err_bcn;
  858. }
  859. for (i = DCB_BCN_ATTR_BCNA_0; i <= DCB_BCN_ATTR_RI; i++) {
  860. if (!getall && !bcn_tb[i])
  861. continue;
  862. netdev->dcbnl_ops->getbcncfg(netdev, i,
  863. &value_integer);
  864. ret = nla_put_u32(dcbnl_skb, i, value_integer);
  865. if (ret)
  866. goto err_bcn;
  867. }
  868. nla_nest_end(dcbnl_skb, bcn_nest);
  869. nlmsg_end(dcbnl_skb, nlh);
  870. ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
  871. if (ret)
  872. goto err_out;
  873. return 0;
  874. err_bcn:
  875. nla_nest_cancel(dcbnl_skb, bcn_nest);
  876. nlmsg_failure:
  877. err:
  878. kfree_skb(dcbnl_skb);
  879. err_out:
  880. ret = -EINVAL;
  881. return ret;
  882. }
  883. static int dcbnl_bcn_setcfg(struct net_device *netdev, struct nlattr **tb,
  884. u32 pid, u32 seq, u16 flags)
  885. {
  886. struct nlattr *data[DCB_BCN_ATTR_MAX + 1];
  887. int i;
  888. int ret = -EINVAL;
  889. u8 value_byte;
  890. u32 value_int;
  891. if (!tb[DCB_ATTR_BCN] || !netdev->dcbnl_ops->setbcncfg
  892. || !netdev->dcbnl_ops->setbcnrp)
  893. return ret;
  894. ret = nla_parse_nested(data, DCB_BCN_ATTR_MAX,
  895. tb[DCB_ATTR_BCN],
  896. dcbnl_pfc_up_nest);
  897. if (ret)
  898. goto err;
  899. for (i = DCB_BCN_ATTR_RP_0; i <= DCB_BCN_ATTR_RP_7; i++) {
  900. if (data[i] == NULL)
  901. continue;
  902. value_byte = nla_get_u8(data[i]);
  903. netdev->dcbnl_ops->setbcnrp(netdev,
  904. data[i]->nla_type - DCB_BCN_ATTR_RP_0, value_byte);
  905. }
  906. for (i = DCB_BCN_ATTR_BCNA_0; i <= DCB_BCN_ATTR_RI; i++) {
  907. if (data[i] == NULL)
  908. continue;
  909. value_int = nla_get_u32(data[i]);
  910. netdev->dcbnl_ops->setbcncfg(netdev,
  911. i, value_int);
  912. }
  913. ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_BCN_SCFG, DCB_ATTR_BCN,
  914. pid, seq, flags);
  915. err:
  916. return ret;
  917. }
  918. static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
  919. {
  920. struct net *net = sock_net(skb->sk);
  921. struct net_device *netdev;
  922. struct dcbmsg *dcb = (struct dcbmsg *)NLMSG_DATA(nlh);
  923. struct nlattr *tb[DCB_ATTR_MAX + 1];
  924. u32 pid = skb ? NETLINK_CB(skb).pid : 0;
  925. int ret = -EINVAL;
  926. if (net != &init_net)
  927. return -EINVAL;
  928. ret = nlmsg_parse(nlh, sizeof(*dcb), tb, DCB_ATTR_MAX,
  929. dcbnl_rtnl_policy);
  930. if (ret < 0)
  931. return ret;
  932. if (!tb[DCB_ATTR_IFNAME])
  933. return -EINVAL;
  934. netdev = dev_get_by_name(&init_net, nla_data(tb[DCB_ATTR_IFNAME]));
  935. if (!netdev)
  936. return -EINVAL;
  937. if (!netdev->dcbnl_ops)
  938. goto errout;
  939. switch (dcb->cmd) {
  940. case DCB_CMD_GSTATE:
  941. ret = dcbnl_getstate(netdev, tb, pid, nlh->nlmsg_seq,
  942. nlh->nlmsg_flags);
  943. goto out;
  944. case DCB_CMD_PFC_GCFG:
  945. ret = dcbnl_getpfccfg(netdev, tb, pid, nlh->nlmsg_seq,
  946. nlh->nlmsg_flags);
  947. goto out;
  948. case DCB_CMD_GPERM_HWADDR:
  949. ret = dcbnl_getperm_hwaddr(netdev, tb, pid, nlh->nlmsg_seq,
  950. nlh->nlmsg_flags);
  951. goto out;
  952. case DCB_CMD_PGTX_GCFG:
  953. ret = dcbnl_pgtx_getcfg(netdev, tb, pid, nlh->nlmsg_seq,
  954. nlh->nlmsg_flags);
  955. goto out;
  956. case DCB_CMD_PGRX_GCFG:
  957. ret = dcbnl_pgrx_getcfg(netdev, tb, pid, nlh->nlmsg_seq,
  958. nlh->nlmsg_flags);
  959. goto out;
  960. case DCB_CMD_BCN_GCFG:
  961. ret = dcbnl_bcn_getcfg(netdev, tb, pid, nlh->nlmsg_seq,
  962. nlh->nlmsg_flags);
  963. goto out;
  964. case DCB_CMD_SSTATE:
  965. ret = dcbnl_setstate(netdev, tb, pid, nlh->nlmsg_seq,
  966. nlh->nlmsg_flags);
  967. goto out;
  968. case DCB_CMD_PFC_SCFG:
  969. ret = dcbnl_setpfccfg(netdev, tb, pid, nlh->nlmsg_seq,
  970. nlh->nlmsg_flags);
  971. goto out;
  972. case DCB_CMD_SET_ALL:
  973. ret = dcbnl_setall(netdev, tb, pid, nlh->nlmsg_seq,
  974. nlh->nlmsg_flags);
  975. goto out;
  976. case DCB_CMD_PGTX_SCFG:
  977. ret = dcbnl_pgtx_setcfg(netdev, tb, pid, nlh->nlmsg_seq,
  978. nlh->nlmsg_flags);
  979. goto out;
  980. case DCB_CMD_PGRX_SCFG:
  981. ret = dcbnl_pgrx_setcfg(netdev, tb, pid, nlh->nlmsg_seq,
  982. nlh->nlmsg_flags);
  983. goto out;
  984. case DCB_CMD_GCAP:
  985. ret = dcbnl_getcap(netdev, tb, pid, nlh->nlmsg_seq,
  986. nlh->nlmsg_flags);
  987. goto out;
  988. case DCB_CMD_GNUMTCS:
  989. ret = dcbnl_getnumtcs(netdev, tb, pid, nlh->nlmsg_seq,
  990. nlh->nlmsg_flags);
  991. goto out;
  992. case DCB_CMD_SNUMTCS:
  993. ret = dcbnl_setnumtcs(netdev, tb, pid, nlh->nlmsg_seq,
  994. nlh->nlmsg_flags);
  995. goto out;
  996. case DCB_CMD_PFC_GSTATE:
  997. ret = dcbnl_getpfcstate(netdev, tb, pid, nlh->nlmsg_seq,
  998. nlh->nlmsg_flags);
  999. goto out;
  1000. case DCB_CMD_PFC_SSTATE:
  1001. ret = dcbnl_setpfcstate(netdev, tb, pid, nlh->nlmsg_seq,
  1002. nlh->nlmsg_flags);
  1003. goto out;
  1004. case DCB_CMD_BCN_SCFG:
  1005. ret = dcbnl_bcn_setcfg(netdev, tb, pid, nlh->nlmsg_seq,
  1006. nlh->nlmsg_flags);
  1007. goto out;
  1008. case DCB_CMD_GAPP:
  1009. ret = dcbnl_getapp(netdev, tb, pid, nlh->nlmsg_seq,
  1010. nlh->nlmsg_flags);
  1011. goto out;
  1012. case DCB_CMD_SAPP:
  1013. ret = dcbnl_setapp(netdev, tb, pid, nlh->nlmsg_seq,
  1014. nlh->nlmsg_flags);
  1015. goto out;
  1016. default:
  1017. goto errout;
  1018. }
  1019. errout:
  1020. ret = -EINVAL;
  1021. out:
  1022. dev_put(netdev);
  1023. return ret;
  1024. }
  1025. static int __init dcbnl_init(void)
  1026. {
  1027. rtnl_register(PF_UNSPEC, RTM_GETDCB, dcb_doit, NULL);
  1028. rtnl_register(PF_UNSPEC, RTM_SETDCB, dcb_doit, NULL);
  1029. return 0;
  1030. }
  1031. module_init(dcbnl_init);
  1032. static void __exit dcbnl_exit(void)
  1033. {
  1034. rtnl_unregister(PF_UNSPEC, RTM_GETDCB);
  1035. rtnl_unregister(PF_UNSPEC, RTM_SETDCB);
  1036. }
  1037. module_exit(dcbnl_exit);