blob: 2ff908498924c84373885e40074760b90f3626d4 [file] [log] [blame]
Alexander Duyck2f90b862008-11-20 20:52:10 -08001/*
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
20#include <linux/netdevice.h>
21#include <linux/netlink.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090022#include <linux/slab.h>
Alexander Duyck2f90b862008-11-20 20:52:10 -080023#include <net/netlink.h>
24#include <net/rtnetlink.h>
25#include <linux/dcbnl.h>
26#include <linux/rtnetlink.h>
27#include <net/sock.h>
28
29/**
30 * Data Center Bridging (DCB) is a collection of Ethernet enhancements
31 * intended to allow network traffic with differing requirements
32 * (highly reliable, no drops vs. best effort vs. low latency) to operate
33 * and co-exist on Ethernet. Current DCB features are:
34 *
35 * Enhanced Transmission Selection (aka Priority Grouping [PG]) - provides a
36 * framework for assigning bandwidth guarantees to traffic classes.
37 *
38 * Priority-based Flow Control (PFC) - provides a flow control mechanism which
39 * can work independently for each 802.1p priority.
40 *
41 * Congestion Notification - provides a mechanism for end-to-end congestion
42 * control for protocols which do not have built-in congestion management.
43 *
44 * More information about the emerging standards for these Ethernet features
45 * can be found at: http://www.ieee802.org/1/pages/dcbridges.html
46 *
47 * This file implements an rtnetlink interface to allow configuration of DCB
48 * features for capable devices.
49 */
50
51MODULE_AUTHOR("Lucy Liu, <lucy.liu@intel.com>");
Jeff Kirsher7a6b6f52008-11-25 01:02:08 -080052MODULE_DESCRIPTION("Data Center Bridging netlink interface");
Alexander Duyck2f90b862008-11-20 20:52:10 -080053MODULE_LICENSE("GPL");
54
55/**************** DCB attribute policies *************************************/
56
57/* DCB netlink attributes policy */
Alexey Dobriyanb54452b2010-02-18 08:14:31 +000058static const struct nla_policy dcbnl_rtnl_policy[DCB_ATTR_MAX + 1] = {
Alexander Duyck859ee3c2008-11-20 21:10:23 -080059 [DCB_ATTR_IFNAME] = {.type = NLA_NUL_STRING, .len = IFNAMSIZ - 1},
60 [DCB_ATTR_STATE] = {.type = NLA_U8},
61 [DCB_ATTR_PFC_CFG] = {.type = NLA_NESTED},
62 [DCB_ATTR_PG_CFG] = {.type = NLA_NESTED},
63 [DCB_ATTR_SET_ALL] = {.type = NLA_U8},
Alexander Duyck2f90b862008-11-20 20:52:10 -080064 [DCB_ATTR_PERM_HWADDR] = {.type = NLA_FLAG},
Alexander Duyck859ee3c2008-11-20 21:10:23 -080065 [DCB_ATTR_CAP] = {.type = NLA_NESTED},
66 [DCB_ATTR_PFC_STATE] = {.type = NLA_U8},
67 [DCB_ATTR_BCN] = {.type = NLA_NESTED},
Yi Zou6fa382a2009-08-31 12:33:20 +000068 [DCB_ATTR_APP] = {.type = NLA_NESTED},
John Fastabend3e290272010-12-30 09:25:46 +000069 [DCB_ATTR_IEEE] = {.type = NLA_NESTED},
Alexander Duyck2f90b862008-11-20 20:52:10 -080070};
71
72/* DCB priority flow control to User Priority nested attributes */
Alexey Dobriyanb54452b2010-02-18 08:14:31 +000073static const struct nla_policy dcbnl_pfc_up_nest[DCB_PFC_UP_ATTR_MAX + 1] = {
Alexander Duyck2f90b862008-11-20 20:52:10 -080074 [DCB_PFC_UP_ATTR_0] = {.type = NLA_U8},
75 [DCB_PFC_UP_ATTR_1] = {.type = NLA_U8},
76 [DCB_PFC_UP_ATTR_2] = {.type = NLA_U8},
77 [DCB_PFC_UP_ATTR_3] = {.type = NLA_U8},
78 [DCB_PFC_UP_ATTR_4] = {.type = NLA_U8},
79 [DCB_PFC_UP_ATTR_5] = {.type = NLA_U8},
80 [DCB_PFC_UP_ATTR_6] = {.type = NLA_U8},
81 [DCB_PFC_UP_ATTR_7] = {.type = NLA_U8},
82 [DCB_PFC_UP_ATTR_ALL] = {.type = NLA_FLAG},
83};
84
85/* DCB priority grouping nested attributes */
Alexey Dobriyanb54452b2010-02-18 08:14:31 +000086static const struct nla_policy dcbnl_pg_nest[DCB_PG_ATTR_MAX + 1] = {
Alexander Duyck2f90b862008-11-20 20:52:10 -080087 [DCB_PG_ATTR_TC_0] = {.type = NLA_NESTED},
88 [DCB_PG_ATTR_TC_1] = {.type = NLA_NESTED},
89 [DCB_PG_ATTR_TC_2] = {.type = NLA_NESTED},
90 [DCB_PG_ATTR_TC_3] = {.type = NLA_NESTED},
91 [DCB_PG_ATTR_TC_4] = {.type = NLA_NESTED},
92 [DCB_PG_ATTR_TC_5] = {.type = NLA_NESTED},
93 [DCB_PG_ATTR_TC_6] = {.type = NLA_NESTED},
94 [DCB_PG_ATTR_TC_7] = {.type = NLA_NESTED},
95 [DCB_PG_ATTR_TC_ALL] = {.type = NLA_NESTED},
96 [DCB_PG_ATTR_BW_ID_0] = {.type = NLA_U8},
97 [DCB_PG_ATTR_BW_ID_1] = {.type = NLA_U8},
98 [DCB_PG_ATTR_BW_ID_2] = {.type = NLA_U8},
99 [DCB_PG_ATTR_BW_ID_3] = {.type = NLA_U8},
100 [DCB_PG_ATTR_BW_ID_4] = {.type = NLA_U8},
101 [DCB_PG_ATTR_BW_ID_5] = {.type = NLA_U8},
102 [DCB_PG_ATTR_BW_ID_6] = {.type = NLA_U8},
103 [DCB_PG_ATTR_BW_ID_7] = {.type = NLA_U8},
104 [DCB_PG_ATTR_BW_ID_ALL] = {.type = NLA_FLAG},
105};
106
107/* DCB traffic class nested attributes. */
Alexey Dobriyanb54452b2010-02-18 08:14:31 +0000108static const struct nla_policy dcbnl_tc_param_nest[DCB_TC_ATTR_PARAM_MAX + 1] = {
Alexander Duyck2f90b862008-11-20 20:52:10 -0800109 [DCB_TC_ATTR_PARAM_PGID] = {.type = NLA_U8},
110 [DCB_TC_ATTR_PARAM_UP_MAPPING] = {.type = NLA_U8},
111 [DCB_TC_ATTR_PARAM_STRICT_PRIO] = {.type = NLA_U8},
112 [DCB_TC_ATTR_PARAM_BW_PCT] = {.type = NLA_U8},
113 [DCB_TC_ATTR_PARAM_ALL] = {.type = NLA_FLAG},
114};
115
Alexander Duyck46132182008-11-20 21:05:08 -0800116/* DCB capabilities nested attributes. */
Alexey Dobriyanb54452b2010-02-18 08:14:31 +0000117static const struct nla_policy dcbnl_cap_nest[DCB_CAP_ATTR_MAX + 1] = {
Alexander Duyck46132182008-11-20 21:05:08 -0800118 [DCB_CAP_ATTR_ALL] = {.type = NLA_FLAG},
119 [DCB_CAP_ATTR_PG] = {.type = NLA_U8},
120 [DCB_CAP_ATTR_PFC] = {.type = NLA_U8},
121 [DCB_CAP_ATTR_UP2TC] = {.type = NLA_U8},
122 [DCB_CAP_ATTR_PG_TCS] = {.type = NLA_U8},
123 [DCB_CAP_ATTR_PFC_TCS] = {.type = NLA_U8},
124 [DCB_CAP_ATTR_GSP] = {.type = NLA_U8},
125 [DCB_CAP_ATTR_BCN] = {.type = NLA_U8},
126};
Alexander Duyck2f90b862008-11-20 20:52:10 -0800127
Alexander Duyck33dbabc2008-11-20 21:08:19 -0800128/* DCB capabilities nested attributes. */
Alexey Dobriyanb54452b2010-02-18 08:14:31 +0000129static const struct nla_policy dcbnl_numtcs_nest[DCB_NUMTCS_ATTR_MAX + 1] = {
Alexander Duyck33dbabc2008-11-20 21:08:19 -0800130 [DCB_NUMTCS_ATTR_ALL] = {.type = NLA_FLAG},
131 [DCB_NUMTCS_ATTR_PG] = {.type = NLA_U8},
132 [DCB_NUMTCS_ATTR_PFC] = {.type = NLA_U8},
133};
134
Alexander Duyck859ee3c2008-11-20 21:10:23 -0800135/* DCB BCN nested attributes. */
Alexey Dobriyanb54452b2010-02-18 08:14:31 +0000136static const struct nla_policy dcbnl_bcn_nest[DCB_BCN_ATTR_MAX + 1] = {
Alexander Duyck859ee3c2008-11-20 21:10:23 -0800137 [DCB_BCN_ATTR_RP_0] = {.type = NLA_U8},
138 [DCB_BCN_ATTR_RP_1] = {.type = NLA_U8},
139 [DCB_BCN_ATTR_RP_2] = {.type = NLA_U8},
140 [DCB_BCN_ATTR_RP_3] = {.type = NLA_U8},
141 [DCB_BCN_ATTR_RP_4] = {.type = NLA_U8},
142 [DCB_BCN_ATTR_RP_5] = {.type = NLA_U8},
143 [DCB_BCN_ATTR_RP_6] = {.type = NLA_U8},
144 [DCB_BCN_ATTR_RP_7] = {.type = NLA_U8},
145 [DCB_BCN_ATTR_RP_ALL] = {.type = NLA_FLAG},
Don Skidmoref4314e82008-12-21 20:10:29 -0800146 [DCB_BCN_ATTR_BCNA_0] = {.type = NLA_U32},
147 [DCB_BCN_ATTR_BCNA_1] = {.type = NLA_U32},
Alexander Duyck859ee3c2008-11-20 21:10:23 -0800148 [DCB_BCN_ATTR_ALPHA] = {.type = NLA_U32},
149 [DCB_BCN_ATTR_BETA] = {.type = NLA_U32},
150 [DCB_BCN_ATTR_GD] = {.type = NLA_U32},
151 [DCB_BCN_ATTR_GI] = {.type = NLA_U32},
152 [DCB_BCN_ATTR_TMAX] = {.type = NLA_U32},
153 [DCB_BCN_ATTR_TD] = {.type = NLA_U32},
154 [DCB_BCN_ATTR_RMIN] = {.type = NLA_U32},
155 [DCB_BCN_ATTR_W] = {.type = NLA_U32},
156 [DCB_BCN_ATTR_RD] = {.type = NLA_U32},
157 [DCB_BCN_ATTR_RU] = {.type = NLA_U32},
158 [DCB_BCN_ATTR_WRTT] = {.type = NLA_U32},
159 [DCB_BCN_ATTR_RI] = {.type = NLA_U32},
160 [DCB_BCN_ATTR_C] = {.type = NLA_U32},
161 [DCB_BCN_ATTR_ALL] = {.type = NLA_FLAG},
162};
163
Yi Zou6fa382a2009-08-31 12:33:20 +0000164/* DCB APP nested attributes. */
Alexey Dobriyanb54452b2010-02-18 08:14:31 +0000165static const struct nla_policy dcbnl_app_nest[DCB_APP_ATTR_MAX + 1] = {
Yi Zou6fa382a2009-08-31 12:33:20 +0000166 [DCB_APP_ATTR_IDTYPE] = {.type = NLA_U8},
167 [DCB_APP_ATTR_ID] = {.type = NLA_U16},
168 [DCB_APP_ATTR_PRIORITY] = {.type = NLA_U8},
169};
170
John Fastabend3e290272010-12-30 09:25:46 +0000171/* IEEE 802.1Qaz nested attributes. */
172static const struct nla_policy dcbnl_ieee_policy[DCB_ATTR_IEEE_MAX + 1] = {
173 [DCB_ATTR_IEEE_ETS] = {.len = sizeof(struct ieee_ets)},
174 [DCB_ATTR_IEEE_PFC] = {.len = sizeof(struct ieee_pfc)},
175 [DCB_ATTR_IEEE_APP_TABLE] = {.type = NLA_NESTED},
176};
177
178static const struct nla_policy dcbnl_ieee_app[DCB_ATTR_IEEE_APP_MAX + 1] = {
179 [DCB_ATTR_IEEE_APP] = {.len = sizeof(struct dcb_app)},
180};
181
Alexander Duyck2f90b862008-11-20 20:52:10 -0800182/* standard netlink reply call */
183static int dcbnl_reply(u8 value, u8 event, u8 cmd, u8 attr, u32 pid,
184 u32 seq, u16 flags)
185{
186 struct sk_buff *dcbnl_skb;
187 struct dcbmsg *dcb;
188 struct nlmsghdr *nlh;
189 int ret = -EINVAL;
190
191 dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
192 if (!dcbnl_skb)
193 return ret;
194
195 nlh = NLMSG_NEW(dcbnl_skb, pid, seq, event, sizeof(*dcb), flags);
196
197 dcb = NLMSG_DATA(nlh);
198 dcb->dcb_family = AF_UNSPEC;
199 dcb->cmd = cmd;
200 dcb->dcb_pad = 0;
201
202 ret = nla_put_u8(dcbnl_skb, attr, value);
203 if (ret)
204 goto err;
205
206 /* end the message, assign the nlmsg_len. */
207 nlmsg_end(dcbnl_skb, nlh);
208 ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
209 if (ret)
John Fastabend7eaf5072009-09-25 13:12:03 +0000210 return -EINVAL;
Alexander Duyck2f90b862008-11-20 20:52:10 -0800211
212 return 0;
213nlmsg_failure:
214err:
Roel Kluin858eb712009-01-04 17:29:21 -0800215 kfree_skb(dcbnl_skb);
Alexander Duyck2f90b862008-11-20 20:52:10 -0800216 return ret;
217}
218
219static int dcbnl_getstate(struct net_device *netdev, struct nlattr **tb,
220 u32 pid, u32 seq, u16 flags)
221{
222 int ret = -EINVAL;
223
224 /* if (!tb[DCB_ATTR_STATE] || !netdev->dcbnl_ops->getstate) */
225 if (!netdev->dcbnl_ops->getstate)
226 return ret;
227
228 ret = dcbnl_reply(netdev->dcbnl_ops->getstate(netdev), RTM_GETDCB,
229 DCB_CMD_GSTATE, DCB_ATTR_STATE, pid, seq, flags);
230
231 return ret;
232}
233
234static int dcbnl_getpfccfg(struct net_device *netdev, struct nlattr **tb,
235 u32 pid, u32 seq, u16 flags)
236{
237 struct sk_buff *dcbnl_skb;
238 struct nlmsghdr *nlh;
239 struct dcbmsg *dcb;
240 struct nlattr *data[DCB_PFC_UP_ATTR_MAX + 1], *nest;
241 u8 value;
242 int ret = -EINVAL;
243 int i;
244 int getall = 0;
245
246 if (!tb[DCB_ATTR_PFC_CFG] || !netdev->dcbnl_ops->getpfccfg)
247 return ret;
248
249 ret = nla_parse_nested(data, DCB_PFC_UP_ATTR_MAX,
250 tb[DCB_ATTR_PFC_CFG],
251 dcbnl_pfc_up_nest);
252 if (ret)
253 goto err_out;
254
255 dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
256 if (!dcbnl_skb)
257 goto err_out;
258
259 nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
260
261 dcb = NLMSG_DATA(nlh);
262 dcb->dcb_family = AF_UNSPEC;
263 dcb->cmd = DCB_CMD_PFC_GCFG;
264
265 nest = nla_nest_start(dcbnl_skb, DCB_ATTR_PFC_CFG);
266 if (!nest)
267 goto err;
268
269 if (data[DCB_PFC_UP_ATTR_ALL])
270 getall = 1;
271
272 for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) {
273 if (!getall && !data[i])
274 continue;
275
276 netdev->dcbnl_ops->getpfccfg(netdev, i - DCB_PFC_UP_ATTR_0,
277 &value);
278 ret = nla_put_u8(dcbnl_skb, i, value);
279
280 if (ret) {
281 nla_nest_cancel(dcbnl_skb, nest);
282 goto err;
283 }
284 }
285 nla_nest_end(dcbnl_skb, nest);
286
287 nlmsg_end(dcbnl_skb, nlh);
288
289 ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
290 if (ret)
John Fastabend7eaf5072009-09-25 13:12:03 +0000291 goto err_out;
Alexander Duyck2f90b862008-11-20 20:52:10 -0800292
293 return 0;
294nlmsg_failure:
295err:
Roel Kluin858eb712009-01-04 17:29:21 -0800296 kfree_skb(dcbnl_skb);
Alexander Duyck2f90b862008-11-20 20:52:10 -0800297err_out:
298 return -EINVAL;
299}
300
301static int dcbnl_getperm_hwaddr(struct net_device *netdev, struct nlattr **tb,
302 u32 pid, u32 seq, u16 flags)
303{
304 struct sk_buff *dcbnl_skb;
305 struct nlmsghdr *nlh;
306 struct dcbmsg *dcb;
307 u8 perm_addr[MAX_ADDR_LEN];
308 int ret = -EINVAL;
309
310 if (!netdev->dcbnl_ops->getpermhwaddr)
311 return ret;
312
313 dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
314 if (!dcbnl_skb)
315 goto err_out;
316
317 nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
318
319 dcb = NLMSG_DATA(nlh);
320 dcb->dcb_family = AF_UNSPEC;
321 dcb->cmd = DCB_CMD_GPERM_HWADDR;
322
323 netdev->dcbnl_ops->getpermhwaddr(netdev, perm_addr);
324
325 ret = nla_put(dcbnl_skb, DCB_ATTR_PERM_HWADDR, sizeof(perm_addr),
326 perm_addr);
327
328 nlmsg_end(dcbnl_skb, nlh);
329
330 ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
331 if (ret)
John Fastabend7eaf5072009-09-25 13:12:03 +0000332 goto err_out;
Alexander Duyck2f90b862008-11-20 20:52:10 -0800333
334 return 0;
335
336nlmsg_failure:
Roel Kluin858eb712009-01-04 17:29:21 -0800337 kfree_skb(dcbnl_skb);
Alexander Duyck2f90b862008-11-20 20:52:10 -0800338err_out:
339 return -EINVAL;
340}
341
Alexander Duyck46132182008-11-20 21:05:08 -0800342static int dcbnl_getcap(struct net_device *netdev, struct nlattr **tb,
343 u32 pid, u32 seq, u16 flags)
344{
345 struct sk_buff *dcbnl_skb;
346 struct nlmsghdr *nlh;
347 struct dcbmsg *dcb;
348 struct nlattr *data[DCB_CAP_ATTR_MAX + 1], *nest;
349 u8 value;
350 int ret = -EINVAL;
351 int i;
352 int getall = 0;
353
354 if (!tb[DCB_ATTR_CAP] || !netdev->dcbnl_ops->getcap)
355 return ret;
356
357 ret = nla_parse_nested(data, DCB_CAP_ATTR_MAX, tb[DCB_ATTR_CAP],
358 dcbnl_cap_nest);
359 if (ret)
360 goto err_out;
361
362 dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
363 if (!dcbnl_skb)
364 goto err_out;
365
366 nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
367
368 dcb = NLMSG_DATA(nlh);
369 dcb->dcb_family = AF_UNSPEC;
370 dcb->cmd = DCB_CMD_GCAP;
371
372 nest = nla_nest_start(dcbnl_skb, DCB_ATTR_CAP);
373 if (!nest)
374 goto err;
375
376 if (data[DCB_CAP_ATTR_ALL])
377 getall = 1;
378
379 for (i = DCB_CAP_ATTR_ALL+1; i <= DCB_CAP_ATTR_MAX; i++) {
380 if (!getall && !data[i])
381 continue;
382
383 if (!netdev->dcbnl_ops->getcap(netdev, i, &value)) {
384 ret = nla_put_u8(dcbnl_skb, i, value);
385
386 if (ret) {
387 nla_nest_cancel(dcbnl_skb, nest);
388 goto err;
389 }
390 }
391 }
392 nla_nest_end(dcbnl_skb, nest);
393
394 nlmsg_end(dcbnl_skb, nlh);
395
396 ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
397 if (ret)
John Fastabend7eaf5072009-09-25 13:12:03 +0000398 goto err_out;
Alexander Duyck46132182008-11-20 21:05:08 -0800399
400 return 0;
401nlmsg_failure:
402err:
Roel Kluin858eb712009-01-04 17:29:21 -0800403 kfree_skb(dcbnl_skb);
Alexander Duyck46132182008-11-20 21:05:08 -0800404err_out:
405 return -EINVAL;
406}
407
Alexander Duyck33dbabc2008-11-20 21:08:19 -0800408static int dcbnl_getnumtcs(struct net_device *netdev, struct nlattr **tb,
409 u32 pid, u32 seq, u16 flags)
410{
411 struct sk_buff *dcbnl_skb;
412 struct nlmsghdr *nlh;
413 struct dcbmsg *dcb;
414 struct nlattr *data[DCB_NUMTCS_ATTR_MAX + 1], *nest;
415 u8 value;
416 int ret = -EINVAL;
417 int i;
418 int getall = 0;
419
420 if (!tb[DCB_ATTR_NUMTCS] || !netdev->dcbnl_ops->getnumtcs)
421 return ret;
422
423 ret = nla_parse_nested(data, DCB_NUMTCS_ATTR_MAX, tb[DCB_ATTR_NUMTCS],
424 dcbnl_numtcs_nest);
425 if (ret) {
426 ret = -EINVAL;
427 goto err_out;
428 }
429
430 dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
431 if (!dcbnl_skb) {
432 ret = -EINVAL;
433 goto err_out;
434 }
435
436 nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
437
438 dcb = NLMSG_DATA(nlh);
439 dcb->dcb_family = AF_UNSPEC;
440 dcb->cmd = DCB_CMD_GNUMTCS;
441
442 nest = nla_nest_start(dcbnl_skb, DCB_ATTR_NUMTCS);
443 if (!nest) {
444 ret = -EINVAL;
445 goto err;
446 }
447
448 if (data[DCB_NUMTCS_ATTR_ALL])
449 getall = 1;
450
451 for (i = DCB_NUMTCS_ATTR_ALL+1; i <= DCB_NUMTCS_ATTR_MAX; i++) {
452 if (!getall && !data[i])
453 continue;
454
455 ret = netdev->dcbnl_ops->getnumtcs(netdev, i, &value);
456 if (!ret) {
457 ret = nla_put_u8(dcbnl_skb, i, value);
458
459 if (ret) {
460 nla_nest_cancel(dcbnl_skb, nest);
461 ret = -EINVAL;
462 goto err;
463 }
464 } else {
465 goto err;
466 }
467 }
468 nla_nest_end(dcbnl_skb, nest);
469
470 nlmsg_end(dcbnl_skb, nlh);
471
472 ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
473 if (ret) {
474 ret = -EINVAL;
John Fastabend7eaf5072009-09-25 13:12:03 +0000475 goto err_out;
Alexander Duyck33dbabc2008-11-20 21:08:19 -0800476 }
477
478 return 0;
479nlmsg_failure:
480err:
Roel Kluin858eb712009-01-04 17:29:21 -0800481 kfree_skb(dcbnl_skb);
Alexander Duyck33dbabc2008-11-20 21:08:19 -0800482err_out:
483 return ret;
484}
485
486static int dcbnl_setnumtcs(struct net_device *netdev, struct nlattr **tb,
487 u32 pid, u32 seq, u16 flags)
488{
489 struct nlattr *data[DCB_NUMTCS_ATTR_MAX + 1];
490 int ret = -EINVAL;
491 u8 value;
492 int i;
493
Don Skidmore8b124a82008-12-15 01:06:23 -0800494 if (!tb[DCB_ATTR_NUMTCS] || !netdev->dcbnl_ops->setnumtcs)
Alexander Duyck33dbabc2008-11-20 21:08:19 -0800495 return ret;
496
497 ret = nla_parse_nested(data, DCB_NUMTCS_ATTR_MAX, tb[DCB_ATTR_NUMTCS],
498 dcbnl_numtcs_nest);
499
500 if (ret) {
501 ret = -EINVAL;
502 goto err;
503 }
504
505 for (i = DCB_NUMTCS_ATTR_ALL+1; i <= DCB_NUMTCS_ATTR_MAX; i++) {
506 if (data[i] == NULL)
507 continue;
508
509 value = nla_get_u8(data[i]);
510
511 ret = netdev->dcbnl_ops->setnumtcs(netdev, i, value);
512
513 if (ret)
514 goto operr;
515 }
516
517operr:
518 ret = dcbnl_reply(!!ret, RTM_SETDCB, DCB_CMD_SNUMTCS,
519 DCB_ATTR_NUMTCS, pid, seq, flags);
520
521err:
522 return ret;
523}
524
Alexander Duyck0eb3aa92008-11-20 21:09:23 -0800525static int dcbnl_getpfcstate(struct net_device *netdev, struct nlattr **tb,
526 u32 pid, u32 seq, u16 flags)
527{
528 int ret = -EINVAL;
529
530 if (!netdev->dcbnl_ops->getpfcstate)
531 return ret;
532
533 ret = dcbnl_reply(netdev->dcbnl_ops->getpfcstate(netdev), RTM_GETDCB,
534 DCB_CMD_PFC_GSTATE, DCB_ATTR_PFC_STATE,
535 pid, seq, flags);
536
537 return ret;
538}
539
540static int dcbnl_setpfcstate(struct net_device *netdev, struct nlattr **tb,
541 u32 pid, u32 seq, u16 flags)
542{
543 int ret = -EINVAL;
544 u8 value;
545
546 if (!tb[DCB_ATTR_PFC_STATE] || !netdev->dcbnl_ops->setpfcstate)
547 return ret;
548
549 value = nla_get_u8(tb[DCB_ATTR_PFC_STATE]);
550
551 netdev->dcbnl_ops->setpfcstate(netdev, value);
552
553 ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_PFC_SSTATE, DCB_ATTR_PFC_STATE,
554 pid, seq, flags);
555
556 return ret;
557}
558
Yi Zou57949682009-08-31 12:33:40 +0000559static int dcbnl_getapp(struct net_device *netdev, struct nlattr **tb,
560 u32 pid, u32 seq, u16 flags)
561{
562 struct sk_buff *dcbnl_skb;
563 struct nlmsghdr *nlh;
564 struct dcbmsg *dcb;
565 struct nlattr *app_nest;
566 struct nlattr *app_tb[DCB_APP_ATTR_MAX + 1];
567 u16 id;
568 u8 up, idtype;
569 int ret = -EINVAL;
570
571 if (!tb[DCB_ATTR_APP] || !netdev->dcbnl_ops->getapp)
572 goto out;
573
574 ret = nla_parse_nested(app_tb, DCB_APP_ATTR_MAX, tb[DCB_ATTR_APP],
575 dcbnl_app_nest);
576 if (ret)
577 goto out;
578
579 ret = -EINVAL;
580 /* all must be non-null */
581 if ((!app_tb[DCB_APP_ATTR_IDTYPE]) ||
582 (!app_tb[DCB_APP_ATTR_ID]))
583 goto out;
584
585 /* either by eth type or by socket number */
586 idtype = nla_get_u8(app_tb[DCB_APP_ATTR_IDTYPE]);
587 if ((idtype != DCB_APP_IDTYPE_ETHTYPE) &&
588 (idtype != DCB_APP_IDTYPE_PORTNUM))
589 goto out;
590
591 id = nla_get_u16(app_tb[DCB_APP_ATTR_ID]);
592 up = netdev->dcbnl_ops->getapp(netdev, idtype, id);
593
594 /* send this back */
595 dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
596 if (!dcbnl_skb)
597 goto out;
598
599 nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
600 dcb = NLMSG_DATA(nlh);
601 dcb->dcb_family = AF_UNSPEC;
602 dcb->cmd = DCB_CMD_GAPP;
603
604 app_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_APP);
605 ret = nla_put_u8(dcbnl_skb, DCB_APP_ATTR_IDTYPE, idtype);
606 if (ret)
607 goto out_cancel;
608
609 ret = nla_put_u16(dcbnl_skb, DCB_APP_ATTR_ID, id);
610 if (ret)
611 goto out_cancel;
612
613 ret = nla_put_u8(dcbnl_skb, DCB_APP_ATTR_PRIORITY, up);
614 if (ret)
615 goto out_cancel;
616
617 nla_nest_end(dcbnl_skb, app_nest);
618 nlmsg_end(dcbnl_skb, nlh);
619
620 ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
621 if (ret)
622 goto nlmsg_failure;
623
624 goto out;
625
626out_cancel:
627 nla_nest_cancel(dcbnl_skb, app_nest);
628nlmsg_failure:
629 kfree_skb(dcbnl_skb);
630out:
631 return ret;
632}
633
634static int dcbnl_setapp(struct net_device *netdev, struct nlattr **tb,
635 u32 pid, u32 seq, u16 flags)
636{
637 int ret = -EINVAL;
638 u16 id;
639 u8 up, idtype;
640 struct nlattr *app_tb[DCB_APP_ATTR_MAX + 1];
641
642 if (!tb[DCB_ATTR_APP] || !netdev->dcbnl_ops->setapp)
643 goto out;
644
645 ret = nla_parse_nested(app_tb, DCB_APP_ATTR_MAX, tb[DCB_ATTR_APP],
646 dcbnl_app_nest);
647 if (ret)
648 goto out;
649
650 ret = -EINVAL;
651 /* all must be non-null */
652 if ((!app_tb[DCB_APP_ATTR_IDTYPE]) ||
653 (!app_tb[DCB_APP_ATTR_ID]) ||
654 (!app_tb[DCB_APP_ATTR_PRIORITY]))
655 goto out;
656
657 /* either by eth type or by socket number */
658 idtype = nla_get_u8(app_tb[DCB_APP_ATTR_IDTYPE]);
659 if ((idtype != DCB_APP_IDTYPE_ETHTYPE) &&
660 (idtype != DCB_APP_IDTYPE_PORTNUM))
661 goto out;
662
663 id = nla_get_u16(app_tb[DCB_APP_ATTR_ID]);
664 up = nla_get_u8(app_tb[DCB_APP_ATTR_PRIORITY]);
665
666 ret = dcbnl_reply(netdev->dcbnl_ops->setapp(netdev, idtype, id, up),
667 RTM_SETDCB, DCB_CMD_SAPP, DCB_ATTR_APP,
668 pid, seq, flags);
669out:
670 return ret;
671}
672
Alexander Duyck2f90b862008-11-20 20:52:10 -0800673static int __dcbnl_pg_getcfg(struct net_device *netdev, struct nlattr **tb,
674 u32 pid, u32 seq, u16 flags, int dir)
675{
676 struct sk_buff *dcbnl_skb;
677 struct nlmsghdr *nlh;
678 struct dcbmsg *dcb;
679 struct nlattr *pg_nest, *param_nest, *data;
680 struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1];
681 struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1];
682 u8 prio, pgid, tc_pct, up_map;
683 int ret = -EINVAL;
684 int getall = 0;
685 int i;
686
687 if (!tb[DCB_ATTR_PG_CFG] ||
688 !netdev->dcbnl_ops->getpgtccfgtx ||
689 !netdev->dcbnl_ops->getpgtccfgrx ||
690 !netdev->dcbnl_ops->getpgbwgcfgtx ||
691 !netdev->dcbnl_ops->getpgbwgcfgrx)
692 return ret;
693
694 ret = nla_parse_nested(pg_tb, DCB_PG_ATTR_MAX,
695 tb[DCB_ATTR_PG_CFG], dcbnl_pg_nest);
696
697 if (ret)
698 goto err_out;
699
700 dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
701 if (!dcbnl_skb)
702 goto err_out;
703
704 nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
705
706 dcb = NLMSG_DATA(nlh);
707 dcb->dcb_family = AF_UNSPEC;
708 dcb->cmd = (dir) ? DCB_CMD_PGRX_GCFG : DCB_CMD_PGTX_GCFG;
709
710 pg_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_PG_CFG);
711 if (!pg_nest)
712 goto err;
713
714 if (pg_tb[DCB_PG_ATTR_TC_ALL])
715 getall = 1;
716
717 for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) {
718 if (!getall && !pg_tb[i])
719 continue;
720
721 if (pg_tb[DCB_PG_ATTR_TC_ALL])
722 data = pg_tb[DCB_PG_ATTR_TC_ALL];
723 else
724 data = pg_tb[i];
725 ret = nla_parse_nested(param_tb, DCB_TC_ATTR_PARAM_MAX,
726 data, dcbnl_tc_param_nest);
727 if (ret)
728 goto err_pg;
729
730 param_nest = nla_nest_start(dcbnl_skb, i);
731 if (!param_nest)
732 goto err_pg;
733
734 pgid = DCB_ATTR_VALUE_UNDEFINED;
735 prio = DCB_ATTR_VALUE_UNDEFINED;
736 tc_pct = DCB_ATTR_VALUE_UNDEFINED;
737 up_map = DCB_ATTR_VALUE_UNDEFINED;
738
739 if (dir) {
740 /* Rx */
741 netdev->dcbnl_ops->getpgtccfgrx(netdev,
742 i - DCB_PG_ATTR_TC_0, &prio,
743 &pgid, &tc_pct, &up_map);
744 } else {
745 /* Tx */
746 netdev->dcbnl_ops->getpgtccfgtx(netdev,
747 i - DCB_PG_ATTR_TC_0, &prio,
748 &pgid, &tc_pct, &up_map);
749 }
750
751 if (param_tb[DCB_TC_ATTR_PARAM_PGID] ||
752 param_tb[DCB_TC_ATTR_PARAM_ALL]) {
753 ret = nla_put_u8(dcbnl_skb,
754 DCB_TC_ATTR_PARAM_PGID, pgid);
755 if (ret)
756 goto err_param;
757 }
758 if (param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING] ||
759 param_tb[DCB_TC_ATTR_PARAM_ALL]) {
760 ret = nla_put_u8(dcbnl_skb,
761 DCB_TC_ATTR_PARAM_UP_MAPPING, up_map);
762 if (ret)
763 goto err_param;
764 }
765 if (param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO] ||
766 param_tb[DCB_TC_ATTR_PARAM_ALL]) {
767 ret = nla_put_u8(dcbnl_skb,
768 DCB_TC_ATTR_PARAM_STRICT_PRIO, prio);
769 if (ret)
770 goto err_param;
771 }
772 if (param_tb[DCB_TC_ATTR_PARAM_BW_PCT] ||
773 param_tb[DCB_TC_ATTR_PARAM_ALL]) {
774 ret = nla_put_u8(dcbnl_skb, DCB_TC_ATTR_PARAM_BW_PCT,
775 tc_pct);
776 if (ret)
777 goto err_param;
778 }
779 nla_nest_end(dcbnl_skb, param_nest);
780 }
781
782 if (pg_tb[DCB_PG_ATTR_BW_ID_ALL])
783 getall = 1;
784 else
785 getall = 0;
786
787 for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) {
788 if (!getall && !pg_tb[i])
789 continue;
790
791 tc_pct = DCB_ATTR_VALUE_UNDEFINED;
792
793 if (dir) {
794 /* Rx */
795 netdev->dcbnl_ops->getpgbwgcfgrx(netdev,
796 i - DCB_PG_ATTR_BW_ID_0, &tc_pct);
797 } else {
798 /* Tx */
799 netdev->dcbnl_ops->getpgbwgcfgtx(netdev,
800 i - DCB_PG_ATTR_BW_ID_0, &tc_pct);
801 }
802 ret = nla_put_u8(dcbnl_skb, i, tc_pct);
803
804 if (ret)
805 goto err_pg;
806 }
807
808 nla_nest_end(dcbnl_skb, pg_nest);
809
810 nlmsg_end(dcbnl_skb, nlh);
811
812 ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
813 if (ret)
John Fastabend7eaf5072009-09-25 13:12:03 +0000814 goto err_out;
Alexander Duyck2f90b862008-11-20 20:52:10 -0800815
816 return 0;
817
818err_param:
819 nla_nest_cancel(dcbnl_skb, param_nest);
820err_pg:
821 nla_nest_cancel(dcbnl_skb, pg_nest);
822nlmsg_failure:
823err:
Roel Kluin858eb712009-01-04 17:29:21 -0800824 kfree_skb(dcbnl_skb);
Alexander Duyck2f90b862008-11-20 20:52:10 -0800825err_out:
826 ret = -EINVAL;
827 return ret;
828}
829
830static int dcbnl_pgtx_getcfg(struct net_device *netdev, struct nlattr **tb,
831 u32 pid, u32 seq, u16 flags)
832{
833 return __dcbnl_pg_getcfg(netdev, tb, pid, seq, flags, 0);
834}
835
836static int dcbnl_pgrx_getcfg(struct net_device *netdev, struct nlattr **tb,
837 u32 pid, u32 seq, u16 flags)
838{
839 return __dcbnl_pg_getcfg(netdev, tb, pid, seq, flags, 1);
840}
841
842static int dcbnl_setstate(struct net_device *netdev, struct nlattr **tb,
843 u32 pid, u32 seq, u16 flags)
844{
845 int ret = -EINVAL;
846 u8 value;
847
848 if (!tb[DCB_ATTR_STATE] || !netdev->dcbnl_ops->setstate)
849 return ret;
850
851 value = nla_get_u8(tb[DCB_ATTR_STATE]);
852
Don Skidmore1486a612008-12-21 20:09:50 -0800853 ret = dcbnl_reply(netdev->dcbnl_ops->setstate(netdev, value),
854 RTM_SETDCB, DCB_CMD_SSTATE, DCB_ATTR_STATE,
Alexander Duyck2f90b862008-11-20 20:52:10 -0800855 pid, seq, flags);
856
857 return ret;
858}
859
860static int dcbnl_setpfccfg(struct net_device *netdev, struct nlattr **tb,
861 u32 pid, u32 seq, u16 flags)
862{
863 struct nlattr *data[DCB_PFC_UP_ATTR_MAX + 1];
864 int i;
865 int ret = -EINVAL;
866 u8 value;
867
868 if (!tb[DCB_ATTR_PFC_CFG] || !netdev->dcbnl_ops->setpfccfg)
869 return ret;
870
871 ret = nla_parse_nested(data, DCB_PFC_UP_ATTR_MAX,
872 tb[DCB_ATTR_PFC_CFG],
873 dcbnl_pfc_up_nest);
874 if (ret)
875 goto err;
876
877 for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) {
878 if (data[i] == NULL)
879 continue;
880 value = nla_get_u8(data[i]);
881 netdev->dcbnl_ops->setpfccfg(netdev,
882 data[i]->nla_type - DCB_PFC_UP_ATTR_0, value);
883 }
884
885 ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_PFC_SCFG, DCB_ATTR_PFC_CFG,
886 pid, seq, flags);
887err:
888 return ret;
889}
890
891static int dcbnl_setall(struct net_device *netdev, struct nlattr **tb,
892 u32 pid, u32 seq, u16 flags)
893{
894 int ret = -EINVAL;
895
896 if (!tb[DCB_ATTR_SET_ALL] || !netdev->dcbnl_ops->setall)
897 return ret;
898
899 ret = dcbnl_reply(netdev->dcbnl_ops->setall(netdev), RTM_SETDCB,
900 DCB_CMD_SET_ALL, DCB_ATTR_SET_ALL, pid, seq, flags);
901
902 return ret;
903}
904
905static int __dcbnl_pg_setcfg(struct net_device *netdev, struct nlattr **tb,
906 u32 pid, u32 seq, u16 flags, int dir)
907{
908 struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1];
909 struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1];
910 int ret = -EINVAL;
911 int i;
912 u8 pgid;
913 u8 up_map;
914 u8 prio;
915 u8 tc_pct;
916
917 if (!tb[DCB_ATTR_PG_CFG] ||
918 !netdev->dcbnl_ops->setpgtccfgtx ||
919 !netdev->dcbnl_ops->setpgtccfgrx ||
920 !netdev->dcbnl_ops->setpgbwgcfgtx ||
921 !netdev->dcbnl_ops->setpgbwgcfgrx)
922 return ret;
923
924 ret = nla_parse_nested(pg_tb, DCB_PG_ATTR_MAX,
925 tb[DCB_ATTR_PG_CFG], dcbnl_pg_nest);
926 if (ret)
927 goto err;
928
929 for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) {
930 if (!pg_tb[i])
931 continue;
932
933 ret = nla_parse_nested(param_tb, DCB_TC_ATTR_PARAM_MAX,
934 pg_tb[i], dcbnl_tc_param_nest);
935 if (ret)
936 goto err;
937
938 pgid = DCB_ATTR_VALUE_UNDEFINED;
939 prio = DCB_ATTR_VALUE_UNDEFINED;
940 tc_pct = DCB_ATTR_VALUE_UNDEFINED;
941 up_map = DCB_ATTR_VALUE_UNDEFINED;
942
943 if (param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO])
944 prio =
945 nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO]);
946
947 if (param_tb[DCB_TC_ATTR_PARAM_PGID])
948 pgid = nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_PGID]);
949
950 if (param_tb[DCB_TC_ATTR_PARAM_BW_PCT])
951 tc_pct = nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_BW_PCT]);
952
953 if (param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING])
954 up_map =
955 nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING]);
956
957 /* dir: Tx = 0, Rx = 1 */
958 if (dir) {
959 /* Rx */
960 netdev->dcbnl_ops->setpgtccfgrx(netdev,
961 i - DCB_PG_ATTR_TC_0,
962 prio, pgid, tc_pct, up_map);
963 } else {
964 /* Tx */
965 netdev->dcbnl_ops->setpgtccfgtx(netdev,
966 i - DCB_PG_ATTR_TC_0,
967 prio, pgid, tc_pct, up_map);
968 }
969 }
970
971 for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) {
972 if (!pg_tb[i])
973 continue;
974
975 tc_pct = nla_get_u8(pg_tb[i]);
976
977 /* dir: Tx = 0, Rx = 1 */
978 if (dir) {
979 /* Rx */
980 netdev->dcbnl_ops->setpgbwgcfgrx(netdev,
981 i - DCB_PG_ATTR_BW_ID_0, tc_pct);
982 } else {
983 /* Tx */
984 netdev->dcbnl_ops->setpgbwgcfgtx(netdev,
985 i - DCB_PG_ATTR_BW_ID_0, tc_pct);
986 }
987 }
988
989 ret = dcbnl_reply(0, RTM_SETDCB,
990 (dir ? DCB_CMD_PGRX_SCFG : DCB_CMD_PGTX_SCFG),
991 DCB_ATTR_PG_CFG, pid, seq, flags);
992
993err:
994 return ret;
995}
996
997static int dcbnl_pgtx_setcfg(struct net_device *netdev, struct nlattr **tb,
998 u32 pid, u32 seq, u16 flags)
999{
1000 return __dcbnl_pg_setcfg(netdev, tb, pid, seq, flags, 0);
1001}
1002
1003static int dcbnl_pgrx_setcfg(struct net_device *netdev, struct nlattr **tb,
1004 u32 pid, u32 seq, u16 flags)
1005{
1006 return __dcbnl_pg_setcfg(netdev, tb, pid, seq, flags, 1);
1007}
1008
Alexander Duyck859ee3c2008-11-20 21:10:23 -08001009static int dcbnl_bcn_getcfg(struct net_device *netdev, struct nlattr **tb,
1010 u32 pid, u32 seq, u16 flags)
1011{
1012 struct sk_buff *dcbnl_skb;
1013 struct nlmsghdr *nlh;
1014 struct dcbmsg *dcb;
1015 struct nlattr *bcn_nest;
1016 struct nlattr *bcn_tb[DCB_BCN_ATTR_MAX + 1];
1017 u8 value_byte;
1018 u32 value_integer;
1019 int ret = -EINVAL;
1020 bool getall = false;
1021 int i;
1022
1023 if (!tb[DCB_ATTR_BCN] || !netdev->dcbnl_ops->getbcnrp ||
1024 !netdev->dcbnl_ops->getbcncfg)
1025 return ret;
1026
1027 ret = nla_parse_nested(bcn_tb, DCB_BCN_ATTR_MAX,
1028 tb[DCB_ATTR_BCN], dcbnl_bcn_nest);
1029
1030 if (ret)
1031 goto err_out;
1032
1033 dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1034 if (!dcbnl_skb)
1035 goto err_out;
1036
1037 nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
1038
1039 dcb = NLMSG_DATA(nlh);
1040 dcb->dcb_family = AF_UNSPEC;
1041 dcb->cmd = DCB_CMD_BCN_GCFG;
1042
1043 bcn_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_BCN);
1044 if (!bcn_nest)
1045 goto err;
1046
1047 if (bcn_tb[DCB_BCN_ATTR_ALL])
1048 getall = true;
1049
1050 for (i = DCB_BCN_ATTR_RP_0; i <= DCB_BCN_ATTR_RP_7; i++) {
1051 if (!getall && !bcn_tb[i])
1052 continue;
1053
1054 netdev->dcbnl_ops->getbcnrp(netdev, i - DCB_BCN_ATTR_RP_0,
1055 &value_byte);
1056 ret = nla_put_u8(dcbnl_skb, i, value_byte);
1057 if (ret)
1058 goto err_bcn;
1059 }
1060
Don Skidmoref4314e82008-12-21 20:10:29 -08001061 for (i = DCB_BCN_ATTR_BCNA_0; i <= DCB_BCN_ATTR_RI; i++) {
Alexander Duyck859ee3c2008-11-20 21:10:23 -08001062 if (!getall && !bcn_tb[i])
1063 continue;
1064
1065 netdev->dcbnl_ops->getbcncfg(netdev, i,
1066 &value_integer);
1067 ret = nla_put_u32(dcbnl_skb, i, value_integer);
1068 if (ret)
1069 goto err_bcn;
1070 }
1071
1072 nla_nest_end(dcbnl_skb, bcn_nest);
1073
1074 nlmsg_end(dcbnl_skb, nlh);
1075
1076 ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
1077 if (ret)
John Fastabend7eaf5072009-09-25 13:12:03 +00001078 goto err_out;
Alexander Duyck859ee3c2008-11-20 21:10:23 -08001079
1080 return 0;
1081
1082err_bcn:
1083 nla_nest_cancel(dcbnl_skb, bcn_nest);
1084nlmsg_failure:
1085err:
Roel Kluin858eb712009-01-04 17:29:21 -08001086 kfree_skb(dcbnl_skb);
Alexander Duyck859ee3c2008-11-20 21:10:23 -08001087err_out:
1088 ret = -EINVAL;
1089 return ret;
1090}
1091
1092static int dcbnl_bcn_setcfg(struct net_device *netdev, struct nlattr **tb,
1093 u32 pid, u32 seq, u16 flags)
1094{
1095 struct nlattr *data[DCB_BCN_ATTR_MAX + 1];
1096 int i;
1097 int ret = -EINVAL;
1098 u8 value_byte;
1099 u32 value_int;
1100
Joe Perchesf64f9e72009-11-29 16:55:45 -08001101 if (!tb[DCB_ATTR_BCN] || !netdev->dcbnl_ops->setbcncfg ||
1102 !netdev->dcbnl_ops->setbcnrp)
Alexander Duyck859ee3c2008-11-20 21:10:23 -08001103 return ret;
1104
1105 ret = nla_parse_nested(data, DCB_BCN_ATTR_MAX,
1106 tb[DCB_ATTR_BCN],
1107 dcbnl_pfc_up_nest);
1108 if (ret)
1109 goto err;
1110
1111 for (i = DCB_BCN_ATTR_RP_0; i <= DCB_BCN_ATTR_RP_7; i++) {
1112 if (data[i] == NULL)
1113 continue;
1114 value_byte = nla_get_u8(data[i]);
1115 netdev->dcbnl_ops->setbcnrp(netdev,
1116 data[i]->nla_type - DCB_BCN_ATTR_RP_0, value_byte);
1117 }
1118
Don Skidmoref4314e82008-12-21 20:10:29 -08001119 for (i = DCB_BCN_ATTR_BCNA_0; i <= DCB_BCN_ATTR_RI; i++) {
Alexander Duyck859ee3c2008-11-20 21:10:23 -08001120 if (data[i] == NULL)
1121 continue;
1122 value_int = nla_get_u32(data[i]);
1123 netdev->dcbnl_ops->setbcncfg(netdev,
1124 i, value_int);
1125 }
1126
1127 ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_BCN_SCFG, DCB_ATTR_BCN,
1128 pid, seq, flags);
1129err:
1130 return ret;
1131}
1132
John Fastabend3e290272010-12-30 09:25:46 +00001133/* Handle IEEE 802.1Qaz SET commands. If any requested operation can not
1134 * be completed the entire msg is aborted and error value is returned.
1135 * No attempt is made to reconcile the case where only part of the
1136 * cmd can be completed.
1137 */
1138static int dcbnl_ieee_set(struct net_device *netdev, struct nlattr **tb,
1139 u32 pid, u32 seq, u16 flags)
1140{
1141 const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
1142 struct nlattr *ieee[DCB_ATTR_IEEE_MAX + 1];
1143 int err = -EOPNOTSUPP;
1144
1145 if (!ops)
1146 goto err;
1147
1148 err = nla_parse_nested(ieee, DCB_ATTR_IEEE_MAX,
1149 tb[DCB_ATTR_IEEE], dcbnl_ieee_policy);
1150 if (err)
1151 goto err;
1152
1153 if (ieee[DCB_ATTR_IEEE_ETS] && ops->ieee_setets) {
1154 struct ieee_ets *ets = nla_data(ieee[DCB_ATTR_IEEE_ETS]);
1155 err = ops->ieee_setets(netdev, ets);
1156 if (err)
1157 goto err;
1158 }
1159
1160 if (ieee[DCB_ATTR_IEEE_PFC] && ops->ieee_setets) {
1161 struct ieee_pfc *pfc = nla_data(ieee[DCB_ATTR_IEEE_PFC]);
1162 err = ops->ieee_setpfc(netdev, pfc);
1163 if (err)
1164 goto err;
1165 }
1166
1167 if (ieee[DCB_ATTR_IEEE_APP_TABLE] && ops->ieee_setapp) {
1168 struct nlattr *attr;
1169 int rem;
1170
1171 nla_for_each_nested(attr, ieee[DCB_ATTR_IEEE_APP_TABLE], rem) {
1172 struct dcb_app *app_data;
1173 if (nla_type(attr) != DCB_ATTR_IEEE_APP)
1174 continue;
1175 app_data = nla_data(attr);
1176 err = ops->ieee_setapp(netdev, app_data);
1177 if (err)
1178 goto err;
1179 }
1180 }
1181
1182err:
1183 dcbnl_reply(err, RTM_SETDCB, DCB_CMD_IEEE_SET, DCB_ATTR_IEEE,
1184 pid, seq, flags);
1185 return err;
1186}
1187
1188
1189/* Handle IEEE 802.1Qaz GET commands. */
1190static int dcbnl_ieee_get(struct net_device *netdev, struct nlattr **tb,
1191 u32 pid, u32 seq, u16 flags)
1192{
1193 struct sk_buff *skb;
1194 struct nlmsghdr *nlh;
1195 struct dcbmsg *dcb;
1196 struct nlattr *ieee;
1197 const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
1198 int err;
1199
1200 if (!ops)
1201 return -EOPNOTSUPP;
1202
1203 skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1204 if (!skb)
1205 return -ENOBUFS;
1206
1207 nlh = NLMSG_NEW(skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
1208
1209 dcb = NLMSG_DATA(nlh);
1210 dcb->dcb_family = AF_UNSPEC;
1211 dcb->cmd = DCB_CMD_IEEE_GET;
1212
1213 NLA_PUT_STRING(skb, DCB_ATTR_IFNAME, netdev->name);
1214
1215 ieee = nla_nest_start(skb, DCB_ATTR_IEEE);
1216 if (!ieee)
1217 goto nla_put_failure;
1218
1219 if (ops->ieee_getets) {
1220 struct ieee_ets ets;
1221 err = ops->ieee_getets(netdev, &ets);
1222 if (!err)
1223 NLA_PUT(skb, DCB_ATTR_IEEE_ETS, sizeof(ets), &ets);
1224 }
1225
1226 if (ops->ieee_getpfc) {
1227 struct ieee_pfc pfc;
1228 err = ops->ieee_getpfc(netdev, &pfc);
1229 if (!err)
1230 NLA_PUT(skb, DCB_ATTR_IEEE_PFC, sizeof(pfc), &pfc);
1231 }
1232
1233 nla_nest_end(skb, ieee);
1234 nlmsg_end(skb, nlh);
1235
1236 return rtnl_unicast(skb, &init_net, pid);
1237nla_put_failure:
1238 nlmsg_cancel(skb, nlh);
1239nlmsg_failure:
1240 kfree_skb(skb);
1241 return -1;
1242}
1243
Alexander Duyck2f90b862008-11-20 20:52:10 -08001244static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
1245{
1246 struct net *net = sock_net(skb->sk);
1247 struct net_device *netdev;
1248 struct dcbmsg *dcb = (struct dcbmsg *)NLMSG_DATA(nlh);
1249 struct nlattr *tb[DCB_ATTR_MAX + 1];
1250 u32 pid = skb ? NETLINK_CB(skb).pid : 0;
1251 int ret = -EINVAL;
1252
Octavian Purdila09ad9bc2009-11-25 15:14:13 -08001253 if (!net_eq(net, &init_net))
Alexander Duyck2f90b862008-11-20 20:52:10 -08001254 return -EINVAL;
1255
1256 ret = nlmsg_parse(nlh, sizeof(*dcb), tb, DCB_ATTR_MAX,
1257 dcbnl_rtnl_policy);
1258 if (ret < 0)
1259 return ret;
1260
1261 if (!tb[DCB_ATTR_IFNAME])
1262 return -EINVAL;
1263
1264 netdev = dev_get_by_name(&init_net, nla_data(tb[DCB_ATTR_IFNAME]));
1265 if (!netdev)
1266 return -EINVAL;
1267
1268 if (!netdev->dcbnl_ops)
1269 goto errout;
1270
1271 switch (dcb->cmd) {
1272 case DCB_CMD_GSTATE:
1273 ret = dcbnl_getstate(netdev, tb, pid, nlh->nlmsg_seq,
1274 nlh->nlmsg_flags);
1275 goto out;
1276 case DCB_CMD_PFC_GCFG:
1277 ret = dcbnl_getpfccfg(netdev, tb, pid, nlh->nlmsg_seq,
1278 nlh->nlmsg_flags);
1279 goto out;
1280 case DCB_CMD_GPERM_HWADDR:
1281 ret = dcbnl_getperm_hwaddr(netdev, tb, pid, nlh->nlmsg_seq,
1282 nlh->nlmsg_flags);
1283 goto out;
1284 case DCB_CMD_PGTX_GCFG:
1285 ret = dcbnl_pgtx_getcfg(netdev, tb, pid, nlh->nlmsg_seq,
1286 nlh->nlmsg_flags);
1287 goto out;
1288 case DCB_CMD_PGRX_GCFG:
1289 ret = dcbnl_pgrx_getcfg(netdev, tb, pid, nlh->nlmsg_seq,
1290 nlh->nlmsg_flags);
1291 goto out;
Alexander Duyck859ee3c2008-11-20 21:10:23 -08001292 case DCB_CMD_BCN_GCFG:
1293 ret = dcbnl_bcn_getcfg(netdev, tb, pid, nlh->nlmsg_seq,
1294 nlh->nlmsg_flags);
1295 goto out;
Alexander Duyck2f90b862008-11-20 20:52:10 -08001296 case DCB_CMD_SSTATE:
1297 ret = dcbnl_setstate(netdev, tb, pid, nlh->nlmsg_seq,
1298 nlh->nlmsg_flags);
1299 goto out;
1300 case DCB_CMD_PFC_SCFG:
1301 ret = dcbnl_setpfccfg(netdev, tb, pid, nlh->nlmsg_seq,
1302 nlh->nlmsg_flags);
1303 goto out;
1304
1305 case DCB_CMD_SET_ALL:
1306 ret = dcbnl_setall(netdev, tb, pid, nlh->nlmsg_seq,
1307 nlh->nlmsg_flags);
1308 goto out;
1309 case DCB_CMD_PGTX_SCFG:
1310 ret = dcbnl_pgtx_setcfg(netdev, tb, pid, nlh->nlmsg_seq,
1311 nlh->nlmsg_flags);
1312 goto out;
1313 case DCB_CMD_PGRX_SCFG:
1314 ret = dcbnl_pgrx_setcfg(netdev, tb, pid, nlh->nlmsg_seq,
1315 nlh->nlmsg_flags);
1316 goto out;
Alexander Duyck46132182008-11-20 21:05:08 -08001317 case DCB_CMD_GCAP:
1318 ret = dcbnl_getcap(netdev, tb, pid, nlh->nlmsg_seq,
1319 nlh->nlmsg_flags);
1320 goto out;
Alexander Duyck33dbabc2008-11-20 21:08:19 -08001321 case DCB_CMD_GNUMTCS:
1322 ret = dcbnl_getnumtcs(netdev, tb, pid, nlh->nlmsg_seq,
1323 nlh->nlmsg_flags);
1324 goto out;
1325 case DCB_CMD_SNUMTCS:
1326 ret = dcbnl_setnumtcs(netdev, tb, pid, nlh->nlmsg_seq,
1327 nlh->nlmsg_flags);
1328 goto out;
Alexander Duyck0eb3aa92008-11-20 21:09:23 -08001329 case DCB_CMD_PFC_GSTATE:
1330 ret = dcbnl_getpfcstate(netdev, tb, pid, nlh->nlmsg_seq,
1331 nlh->nlmsg_flags);
1332 goto out;
1333 case DCB_CMD_PFC_SSTATE:
1334 ret = dcbnl_setpfcstate(netdev, tb, pid, nlh->nlmsg_seq,
1335 nlh->nlmsg_flags);
1336 goto out;
Alexander Duyck859ee3c2008-11-20 21:10:23 -08001337 case DCB_CMD_BCN_SCFG:
1338 ret = dcbnl_bcn_setcfg(netdev, tb, pid, nlh->nlmsg_seq,
1339 nlh->nlmsg_flags);
1340 goto out;
Yi Zou57949682009-08-31 12:33:40 +00001341 case DCB_CMD_GAPP:
1342 ret = dcbnl_getapp(netdev, tb, pid, nlh->nlmsg_seq,
1343 nlh->nlmsg_flags);
1344 goto out;
1345 case DCB_CMD_SAPP:
1346 ret = dcbnl_setapp(netdev, tb, pid, nlh->nlmsg_seq,
1347 nlh->nlmsg_flags);
1348 goto out;
John Fastabend3e290272010-12-30 09:25:46 +00001349 case DCB_CMD_IEEE_SET:
1350 ret = dcbnl_ieee_set(netdev, tb, pid, nlh->nlmsg_seq,
1351 nlh->nlmsg_flags);
1352 goto out;
1353 case DCB_CMD_IEEE_GET:
1354 ret = dcbnl_ieee_get(netdev, tb, pid, nlh->nlmsg_seq,
1355 nlh->nlmsg_flags);
1356 goto out;
Alexander Duyck2f90b862008-11-20 20:52:10 -08001357 default:
1358 goto errout;
1359 }
1360errout:
1361 ret = -EINVAL;
1362out:
1363 dev_put(netdev);
1364 return ret;
1365}
1366
1367static int __init dcbnl_init(void)
1368{
1369 rtnl_register(PF_UNSPEC, RTM_GETDCB, dcb_doit, NULL);
1370 rtnl_register(PF_UNSPEC, RTM_SETDCB, dcb_doit, NULL);
1371
1372 return 0;
1373}
1374module_init(dcbnl_init);
1375
1376static void __exit dcbnl_exit(void)
1377{
1378 rtnl_unregister(PF_UNSPEC, RTM_GETDCB);
1379 rtnl_unregister(PF_UNSPEC, RTM_SETDCB);
1380}
1381module_exit(dcbnl_exit);
1382
1383