dcbnl.c 32 KB

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