dcbnl.c 29 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130
  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. goto err;
  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;
  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;
  274. return 0;
  275. nlmsg_failure:
  276. err:
  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;
  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;
  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_pg_getcfg(struct net_device *netdev, struct nlattr **tb,
  451. u32 pid, u32 seq, u16 flags, int dir)
  452. {
  453. struct sk_buff *dcbnl_skb;
  454. struct nlmsghdr *nlh;
  455. struct dcbmsg *dcb;
  456. struct nlattr *pg_nest, *param_nest, *data;
  457. struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1];
  458. struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1];
  459. u8 prio, pgid, tc_pct, up_map;
  460. int ret = -EINVAL;
  461. int getall = 0;
  462. int i;
  463. if (!tb[DCB_ATTR_PG_CFG] ||
  464. !netdev->dcbnl_ops->getpgtccfgtx ||
  465. !netdev->dcbnl_ops->getpgtccfgrx ||
  466. !netdev->dcbnl_ops->getpgbwgcfgtx ||
  467. !netdev->dcbnl_ops->getpgbwgcfgrx)
  468. return ret;
  469. ret = nla_parse_nested(pg_tb, DCB_PG_ATTR_MAX,
  470. tb[DCB_ATTR_PG_CFG], dcbnl_pg_nest);
  471. if (ret)
  472. goto err_out;
  473. dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
  474. if (!dcbnl_skb)
  475. goto err_out;
  476. nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
  477. dcb = NLMSG_DATA(nlh);
  478. dcb->dcb_family = AF_UNSPEC;
  479. dcb->cmd = (dir) ? DCB_CMD_PGRX_GCFG : DCB_CMD_PGTX_GCFG;
  480. pg_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_PG_CFG);
  481. if (!pg_nest)
  482. goto err;
  483. if (pg_tb[DCB_PG_ATTR_TC_ALL])
  484. getall = 1;
  485. for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) {
  486. if (!getall && !pg_tb[i])
  487. continue;
  488. if (pg_tb[DCB_PG_ATTR_TC_ALL])
  489. data = pg_tb[DCB_PG_ATTR_TC_ALL];
  490. else
  491. data = pg_tb[i];
  492. ret = nla_parse_nested(param_tb, DCB_TC_ATTR_PARAM_MAX,
  493. data, dcbnl_tc_param_nest);
  494. if (ret)
  495. goto err_pg;
  496. param_nest = nla_nest_start(dcbnl_skb, i);
  497. if (!param_nest)
  498. goto err_pg;
  499. pgid = DCB_ATTR_VALUE_UNDEFINED;
  500. prio = DCB_ATTR_VALUE_UNDEFINED;
  501. tc_pct = DCB_ATTR_VALUE_UNDEFINED;
  502. up_map = DCB_ATTR_VALUE_UNDEFINED;
  503. if (dir) {
  504. /* Rx */
  505. netdev->dcbnl_ops->getpgtccfgrx(netdev,
  506. i - DCB_PG_ATTR_TC_0, &prio,
  507. &pgid, &tc_pct, &up_map);
  508. } else {
  509. /* Tx */
  510. netdev->dcbnl_ops->getpgtccfgtx(netdev,
  511. i - DCB_PG_ATTR_TC_0, &prio,
  512. &pgid, &tc_pct, &up_map);
  513. }
  514. if (param_tb[DCB_TC_ATTR_PARAM_PGID] ||
  515. param_tb[DCB_TC_ATTR_PARAM_ALL]) {
  516. ret = nla_put_u8(dcbnl_skb,
  517. DCB_TC_ATTR_PARAM_PGID, pgid);
  518. if (ret)
  519. goto err_param;
  520. }
  521. if (param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING] ||
  522. param_tb[DCB_TC_ATTR_PARAM_ALL]) {
  523. ret = nla_put_u8(dcbnl_skb,
  524. DCB_TC_ATTR_PARAM_UP_MAPPING, up_map);
  525. if (ret)
  526. goto err_param;
  527. }
  528. if (param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO] ||
  529. param_tb[DCB_TC_ATTR_PARAM_ALL]) {
  530. ret = nla_put_u8(dcbnl_skb,
  531. DCB_TC_ATTR_PARAM_STRICT_PRIO, prio);
  532. if (ret)
  533. goto err_param;
  534. }
  535. if (param_tb[DCB_TC_ATTR_PARAM_BW_PCT] ||
  536. param_tb[DCB_TC_ATTR_PARAM_ALL]) {
  537. ret = nla_put_u8(dcbnl_skb, DCB_TC_ATTR_PARAM_BW_PCT,
  538. tc_pct);
  539. if (ret)
  540. goto err_param;
  541. }
  542. nla_nest_end(dcbnl_skb, param_nest);
  543. }
  544. if (pg_tb[DCB_PG_ATTR_BW_ID_ALL])
  545. getall = 1;
  546. else
  547. getall = 0;
  548. for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) {
  549. if (!getall && !pg_tb[i])
  550. continue;
  551. tc_pct = DCB_ATTR_VALUE_UNDEFINED;
  552. if (dir) {
  553. /* Rx */
  554. netdev->dcbnl_ops->getpgbwgcfgrx(netdev,
  555. i - DCB_PG_ATTR_BW_ID_0, &tc_pct);
  556. } else {
  557. /* Tx */
  558. netdev->dcbnl_ops->getpgbwgcfgtx(netdev,
  559. i - DCB_PG_ATTR_BW_ID_0, &tc_pct);
  560. }
  561. ret = nla_put_u8(dcbnl_skb, i, tc_pct);
  562. if (ret)
  563. goto err_pg;
  564. }
  565. nla_nest_end(dcbnl_skb, pg_nest);
  566. nlmsg_end(dcbnl_skb, nlh);
  567. ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
  568. if (ret)
  569. goto err;
  570. return 0;
  571. err_param:
  572. nla_nest_cancel(dcbnl_skb, param_nest);
  573. err_pg:
  574. nla_nest_cancel(dcbnl_skb, pg_nest);
  575. nlmsg_failure:
  576. err:
  577. kfree_skb(dcbnl_skb);
  578. err_out:
  579. ret = -EINVAL;
  580. return ret;
  581. }
  582. static int dcbnl_pgtx_getcfg(struct net_device *netdev, struct nlattr **tb,
  583. u32 pid, u32 seq, u16 flags)
  584. {
  585. return __dcbnl_pg_getcfg(netdev, tb, pid, seq, flags, 0);
  586. }
  587. static int dcbnl_pgrx_getcfg(struct net_device *netdev, struct nlattr **tb,
  588. u32 pid, u32 seq, u16 flags)
  589. {
  590. return __dcbnl_pg_getcfg(netdev, tb, pid, seq, flags, 1);
  591. }
  592. static int dcbnl_setstate(struct net_device *netdev, struct nlattr **tb,
  593. u32 pid, u32 seq, u16 flags)
  594. {
  595. int ret = -EINVAL;
  596. u8 value;
  597. if (!tb[DCB_ATTR_STATE] || !netdev->dcbnl_ops->setstate)
  598. return ret;
  599. value = nla_get_u8(tb[DCB_ATTR_STATE]);
  600. ret = dcbnl_reply(netdev->dcbnl_ops->setstate(netdev, value),
  601. RTM_SETDCB, DCB_CMD_SSTATE, DCB_ATTR_STATE,
  602. pid, seq, flags);
  603. return ret;
  604. }
  605. static int dcbnl_setpfccfg(struct net_device *netdev, struct nlattr **tb,
  606. u32 pid, u32 seq, u16 flags)
  607. {
  608. struct nlattr *data[DCB_PFC_UP_ATTR_MAX + 1];
  609. int i;
  610. int ret = -EINVAL;
  611. u8 value;
  612. if (!tb[DCB_ATTR_PFC_CFG] || !netdev->dcbnl_ops->setpfccfg)
  613. return ret;
  614. ret = nla_parse_nested(data, DCB_PFC_UP_ATTR_MAX,
  615. tb[DCB_ATTR_PFC_CFG],
  616. dcbnl_pfc_up_nest);
  617. if (ret)
  618. goto err;
  619. for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) {
  620. if (data[i] == NULL)
  621. continue;
  622. value = nla_get_u8(data[i]);
  623. netdev->dcbnl_ops->setpfccfg(netdev,
  624. data[i]->nla_type - DCB_PFC_UP_ATTR_0, value);
  625. }
  626. ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_PFC_SCFG, DCB_ATTR_PFC_CFG,
  627. pid, seq, flags);
  628. err:
  629. return ret;
  630. }
  631. static int dcbnl_setall(struct net_device *netdev, struct nlattr **tb,
  632. u32 pid, u32 seq, u16 flags)
  633. {
  634. int ret = -EINVAL;
  635. if (!tb[DCB_ATTR_SET_ALL] || !netdev->dcbnl_ops->setall)
  636. return ret;
  637. ret = dcbnl_reply(netdev->dcbnl_ops->setall(netdev), RTM_SETDCB,
  638. DCB_CMD_SET_ALL, DCB_ATTR_SET_ALL, pid, seq, flags);
  639. return ret;
  640. }
  641. static int __dcbnl_pg_setcfg(struct net_device *netdev, struct nlattr **tb,
  642. u32 pid, u32 seq, u16 flags, int dir)
  643. {
  644. struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1];
  645. struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1];
  646. int ret = -EINVAL;
  647. int i;
  648. u8 pgid;
  649. u8 up_map;
  650. u8 prio;
  651. u8 tc_pct;
  652. if (!tb[DCB_ATTR_PG_CFG] ||
  653. !netdev->dcbnl_ops->setpgtccfgtx ||
  654. !netdev->dcbnl_ops->setpgtccfgrx ||
  655. !netdev->dcbnl_ops->setpgbwgcfgtx ||
  656. !netdev->dcbnl_ops->setpgbwgcfgrx)
  657. return ret;
  658. ret = nla_parse_nested(pg_tb, DCB_PG_ATTR_MAX,
  659. tb[DCB_ATTR_PG_CFG], dcbnl_pg_nest);
  660. if (ret)
  661. goto err;
  662. for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) {
  663. if (!pg_tb[i])
  664. continue;
  665. ret = nla_parse_nested(param_tb, DCB_TC_ATTR_PARAM_MAX,
  666. pg_tb[i], dcbnl_tc_param_nest);
  667. if (ret)
  668. goto err;
  669. pgid = DCB_ATTR_VALUE_UNDEFINED;
  670. prio = DCB_ATTR_VALUE_UNDEFINED;
  671. tc_pct = DCB_ATTR_VALUE_UNDEFINED;
  672. up_map = DCB_ATTR_VALUE_UNDEFINED;
  673. if (param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO])
  674. prio =
  675. nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO]);
  676. if (param_tb[DCB_TC_ATTR_PARAM_PGID])
  677. pgid = nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_PGID]);
  678. if (param_tb[DCB_TC_ATTR_PARAM_BW_PCT])
  679. tc_pct = nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_BW_PCT]);
  680. if (param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING])
  681. up_map =
  682. nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING]);
  683. /* dir: Tx = 0, Rx = 1 */
  684. if (dir) {
  685. /* Rx */
  686. netdev->dcbnl_ops->setpgtccfgrx(netdev,
  687. i - DCB_PG_ATTR_TC_0,
  688. prio, pgid, tc_pct, up_map);
  689. } else {
  690. /* Tx */
  691. netdev->dcbnl_ops->setpgtccfgtx(netdev,
  692. i - DCB_PG_ATTR_TC_0,
  693. prio, pgid, tc_pct, up_map);
  694. }
  695. }
  696. for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) {
  697. if (!pg_tb[i])
  698. continue;
  699. tc_pct = nla_get_u8(pg_tb[i]);
  700. /* dir: Tx = 0, Rx = 1 */
  701. if (dir) {
  702. /* Rx */
  703. netdev->dcbnl_ops->setpgbwgcfgrx(netdev,
  704. i - DCB_PG_ATTR_BW_ID_0, tc_pct);
  705. } else {
  706. /* Tx */
  707. netdev->dcbnl_ops->setpgbwgcfgtx(netdev,
  708. i - DCB_PG_ATTR_BW_ID_0, tc_pct);
  709. }
  710. }
  711. ret = dcbnl_reply(0, RTM_SETDCB,
  712. (dir ? DCB_CMD_PGRX_SCFG : DCB_CMD_PGTX_SCFG),
  713. DCB_ATTR_PG_CFG, pid, seq, flags);
  714. err:
  715. return ret;
  716. }
  717. static int dcbnl_pgtx_setcfg(struct net_device *netdev, struct nlattr **tb,
  718. u32 pid, u32 seq, u16 flags)
  719. {
  720. return __dcbnl_pg_setcfg(netdev, tb, pid, seq, flags, 0);
  721. }
  722. static int dcbnl_pgrx_setcfg(struct net_device *netdev, struct nlattr **tb,
  723. u32 pid, u32 seq, u16 flags)
  724. {
  725. return __dcbnl_pg_setcfg(netdev, tb, pid, seq, flags, 1);
  726. }
  727. static int dcbnl_bcn_getcfg(struct net_device *netdev, struct nlattr **tb,
  728. u32 pid, u32 seq, u16 flags)
  729. {
  730. struct sk_buff *dcbnl_skb;
  731. struct nlmsghdr *nlh;
  732. struct dcbmsg *dcb;
  733. struct nlattr *bcn_nest;
  734. struct nlattr *bcn_tb[DCB_BCN_ATTR_MAX + 1];
  735. u8 value_byte;
  736. u32 value_integer;
  737. int ret = -EINVAL;
  738. bool getall = false;
  739. int i;
  740. if (!tb[DCB_ATTR_BCN] || !netdev->dcbnl_ops->getbcnrp ||
  741. !netdev->dcbnl_ops->getbcncfg)
  742. return ret;
  743. ret = nla_parse_nested(bcn_tb, DCB_BCN_ATTR_MAX,
  744. tb[DCB_ATTR_BCN], dcbnl_bcn_nest);
  745. if (ret)
  746. goto err_out;
  747. dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
  748. if (!dcbnl_skb)
  749. goto err_out;
  750. nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
  751. dcb = NLMSG_DATA(nlh);
  752. dcb->dcb_family = AF_UNSPEC;
  753. dcb->cmd = DCB_CMD_BCN_GCFG;
  754. bcn_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_BCN);
  755. if (!bcn_nest)
  756. goto err;
  757. if (bcn_tb[DCB_BCN_ATTR_ALL])
  758. getall = true;
  759. for (i = DCB_BCN_ATTR_RP_0; i <= DCB_BCN_ATTR_RP_7; i++) {
  760. if (!getall && !bcn_tb[i])
  761. continue;
  762. netdev->dcbnl_ops->getbcnrp(netdev, i - DCB_BCN_ATTR_RP_0,
  763. &value_byte);
  764. ret = nla_put_u8(dcbnl_skb, i, value_byte);
  765. if (ret)
  766. goto err_bcn;
  767. }
  768. for (i = DCB_BCN_ATTR_BCNA_0; i <= DCB_BCN_ATTR_RI; i++) {
  769. if (!getall && !bcn_tb[i])
  770. continue;
  771. netdev->dcbnl_ops->getbcncfg(netdev, i,
  772. &value_integer);
  773. ret = nla_put_u32(dcbnl_skb, i, value_integer);
  774. if (ret)
  775. goto err_bcn;
  776. }
  777. nla_nest_end(dcbnl_skb, bcn_nest);
  778. nlmsg_end(dcbnl_skb, nlh);
  779. ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
  780. if (ret)
  781. goto err;
  782. return 0;
  783. err_bcn:
  784. nla_nest_cancel(dcbnl_skb, bcn_nest);
  785. nlmsg_failure:
  786. err:
  787. kfree_skb(dcbnl_skb);
  788. err_out:
  789. ret = -EINVAL;
  790. return ret;
  791. }
  792. static int dcbnl_bcn_setcfg(struct net_device *netdev, struct nlattr **tb,
  793. u32 pid, u32 seq, u16 flags)
  794. {
  795. struct nlattr *data[DCB_BCN_ATTR_MAX + 1];
  796. int i;
  797. int ret = -EINVAL;
  798. u8 value_byte;
  799. u32 value_int;
  800. if (!tb[DCB_ATTR_BCN] || !netdev->dcbnl_ops->setbcncfg
  801. || !netdev->dcbnl_ops->setbcnrp)
  802. return ret;
  803. ret = nla_parse_nested(data, DCB_BCN_ATTR_MAX,
  804. tb[DCB_ATTR_BCN],
  805. dcbnl_pfc_up_nest);
  806. if (ret)
  807. goto err;
  808. for (i = DCB_BCN_ATTR_RP_0; i <= DCB_BCN_ATTR_RP_7; i++) {
  809. if (data[i] == NULL)
  810. continue;
  811. value_byte = nla_get_u8(data[i]);
  812. netdev->dcbnl_ops->setbcnrp(netdev,
  813. data[i]->nla_type - DCB_BCN_ATTR_RP_0, value_byte);
  814. }
  815. for (i = DCB_BCN_ATTR_BCNA_0; i <= DCB_BCN_ATTR_RI; i++) {
  816. if (data[i] == NULL)
  817. continue;
  818. value_int = nla_get_u32(data[i]);
  819. netdev->dcbnl_ops->setbcncfg(netdev,
  820. i, value_int);
  821. }
  822. ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_BCN_SCFG, DCB_ATTR_BCN,
  823. pid, seq, flags);
  824. err:
  825. return ret;
  826. }
  827. static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
  828. {
  829. struct net *net = sock_net(skb->sk);
  830. struct net_device *netdev;
  831. struct dcbmsg *dcb = (struct dcbmsg *)NLMSG_DATA(nlh);
  832. struct nlattr *tb[DCB_ATTR_MAX + 1];
  833. u32 pid = skb ? NETLINK_CB(skb).pid : 0;
  834. int ret = -EINVAL;
  835. if (net != &init_net)
  836. return -EINVAL;
  837. ret = nlmsg_parse(nlh, sizeof(*dcb), tb, DCB_ATTR_MAX,
  838. dcbnl_rtnl_policy);
  839. if (ret < 0)
  840. return ret;
  841. if (!tb[DCB_ATTR_IFNAME])
  842. return -EINVAL;
  843. netdev = dev_get_by_name(&init_net, nla_data(tb[DCB_ATTR_IFNAME]));
  844. if (!netdev)
  845. return -EINVAL;
  846. if (!netdev->dcbnl_ops)
  847. goto errout;
  848. switch (dcb->cmd) {
  849. case DCB_CMD_GSTATE:
  850. ret = dcbnl_getstate(netdev, tb, pid, nlh->nlmsg_seq,
  851. nlh->nlmsg_flags);
  852. goto out;
  853. case DCB_CMD_PFC_GCFG:
  854. ret = dcbnl_getpfccfg(netdev, tb, pid, nlh->nlmsg_seq,
  855. nlh->nlmsg_flags);
  856. goto out;
  857. case DCB_CMD_GPERM_HWADDR:
  858. ret = dcbnl_getperm_hwaddr(netdev, tb, pid, nlh->nlmsg_seq,
  859. nlh->nlmsg_flags);
  860. goto out;
  861. case DCB_CMD_PGTX_GCFG:
  862. ret = dcbnl_pgtx_getcfg(netdev, tb, pid, nlh->nlmsg_seq,
  863. nlh->nlmsg_flags);
  864. goto out;
  865. case DCB_CMD_PGRX_GCFG:
  866. ret = dcbnl_pgrx_getcfg(netdev, tb, pid, nlh->nlmsg_seq,
  867. nlh->nlmsg_flags);
  868. goto out;
  869. case DCB_CMD_BCN_GCFG:
  870. ret = dcbnl_bcn_getcfg(netdev, tb, pid, nlh->nlmsg_seq,
  871. nlh->nlmsg_flags);
  872. goto out;
  873. case DCB_CMD_SSTATE:
  874. ret = dcbnl_setstate(netdev, tb, pid, nlh->nlmsg_seq,
  875. nlh->nlmsg_flags);
  876. goto out;
  877. case DCB_CMD_PFC_SCFG:
  878. ret = dcbnl_setpfccfg(netdev, tb, pid, nlh->nlmsg_seq,
  879. nlh->nlmsg_flags);
  880. goto out;
  881. case DCB_CMD_SET_ALL:
  882. ret = dcbnl_setall(netdev, tb, pid, nlh->nlmsg_seq,
  883. nlh->nlmsg_flags);
  884. goto out;
  885. case DCB_CMD_PGTX_SCFG:
  886. ret = dcbnl_pgtx_setcfg(netdev, tb, pid, nlh->nlmsg_seq,
  887. nlh->nlmsg_flags);
  888. goto out;
  889. case DCB_CMD_PGRX_SCFG:
  890. ret = dcbnl_pgrx_setcfg(netdev, tb, pid, nlh->nlmsg_seq,
  891. nlh->nlmsg_flags);
  892. goto out;
  893. case DCB_CMD_GCAP:
  894. ret = dcbnl_getcap(netdev, tb, pid, nlh->nlmsg_seq,
  895. nlh->nlmsg_flags);
  896. goto out;
  897. case DCB_CMD_GNUMTCS:
  898. ret = dcbnl_getnumtcs(netdev, tb, pid, nlh->nlmsg_seq,
  899. nlh->nlmsg_flags);
  900. goto out;
  901. case DCB_CMD_SNUMTCS:
  902. ret = dcbnl_setnumtcs(netdev, tb, pid, nlh->nlmsg_seq,
  903. nlh->nlmsg_flags);
  904. goto out;
  905. case DCB_CMD_PFC_GSTATE:
  906. ret = dcbnl_getpfcstate(netdev, tb, pid, nlh->nlmsg_seq,
  907. nlh->nlmsg_flags);
  908. goto out;
  909. case DCB_CMD_PFC_SSTATE:
  910. ret = dcbnl_setpfcstate(netdev, tb, pid, nlh->nlmsg_seq,
  911. nlh->nlmsg_flags);
  912. goto out;
  913. case DCB_CMD_BCN_SCFG:
  914. ret = dcbnl_bcn_setcfg(netdev, tb, pid, nlh->nlmsg_seq,
  915. nlh->nlmsg_flags);
  916. goto out;
  917. default:
  918. goto errout;
  919. }
  920. errout:
  921. ret = -EINVAL;
  922. out:
  923. dev_put(netdev);
  924. return ret;
  925. }
  926. static int __init dcbnl_init(void)
  927. {
  928. rtnl_register(PF_UNSPEC, RTM_GETDCB, dcb_doit, NULL);
  929. rtnl_register(PF_UNSPEC, RTM_SETDCB, dcb_doit, NULL);
  930. return 0;
  931. }
  932. module_init(dcbnl_init);
  933. static void __exit dcbnl_exit(void)
  934. {
  935. rtnl_unregister(PF_UNSPEC, RTM_GETDCB);
  936. rtnl_unregister(PF_UNSPEC, RTM_SETDCB);
  937. }
  938. module_exit(dcbnl_exit);