blob: 69144125fc4f31aa510c80b688cbba868115c23e [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>
John Fastabend96b99682010-12-30 09:26:37 +000026#include <net/dcbevent.h>
Alexander Duyck2f90b862008-11-20 20:52:10 -080027#include <linux/rtnetlink.h>
28#include <net/sock.h>
29
30/**
31 * Data Center Bridging (DCB) is a collection of Ethernet enhancements
32 * intended to allow network traffic with differing requirements
33 * (highly reliable, no drops vs. best effort vs. low latency) to operate
34 * and co-exist on Ethernet. Current DCB features are:
35 *
36 * Enhanced Transmission Selection (aka Priority Grouping [PG]) - provides a
37 * framework for assigning bandwidth guarantees to traffic classes.
38 *
39 * Priority-based Flow Control (PFC) - provides a flow control mechanism which
40 * can work independently for each 802.1p priority.
41 *
42 * Congestion Notification - provides a mechanism for end-to-end congestion
43 * control for protocols which do not have built-in congestion management.
44 *
45 * More information about the emerging standards for these Ethernet features
46 * can be found at: http://www.ieee802.org/1/pages/dcbridges.html
47 *
48 * This file implements an rtnetlink interface to allow configuration of DCB
49 * features for capable devices.
50 */
51
52MODULE_AUTHOR("Lucy Liu, <lucy.liu@intel.com>");
Jeff Kirsher7a6b6f52008-11-25 01:02:08 -080053MODULE_DESCRIPTION("Data Center Bridging netlink interface");
Alexander Duyck2f90b862008-11-20 20:52:10 -080054MODULE_LICENSE("GPL");
55
56/**************** DCB attribute policies *************************************/
57
58/* DCB netlink attributes policy */
Alexey Dobriyanb54452b2010-02-18 08:14:31 +000059static const struct nla_policy dcbnl_rtnl_policy[DCB_ATTR_MAX + 1] = {
Alexander Duyck859ee3c2008-11-20 21:10:23 -080060 [DCB_ATTR_IFNAME] = {.type = NLA_NUL_STRING, .len = IFNAMSIZ - 1},
61 [DCB_ATTR_STATE] = {.type = NLA_U8},
62 [DCB_ATTR_PFC_CFG] = {.type = NLA_NESTED},
63 [DCB_ATTR_PG_CFG] = {.type = NLA_NESTED},
64 [DCB_ATTR_SET_ALL] = {.type = NLA_U8},
Alexander Duyck2f90b862008-11-20 20:52:10 -080065 [DCB_ATTR_PERM_HWADDR] = {.type = NLA_FLAG},
Alexander Duyck859ee3c2008-11-20 21:10:23 -080066 [DCB_ATTR_CAP] = {.type = NLA_NESTED},
67 [DCB_ATTR_PFC_STATE] = {.type = NLA_U8},
68 [DCB_ATTR_BCN] = {.type = NLA_NESTED},
Yi Zou6fa382a2009-08-31 12:33:20 +000069 [DCB_ATTR_APP] = {.type = NLA_NESTED},
John Fastabend3e290272010-12-30 09:25:46 +000070 [DCB_ATTR_IEEE] = {.type = NLA_NESTED},
Alexander Duyck2f90b862008-11-20 20:52:10 -080071};
72
73/* DCB priority flow control to User Priority nested attributes */
Alexey Dobriyanb54452b2010-02-18 08:14:31 +000074static const struct nla_policy dcbnl_pfc_up_nest[DCB_PFC_UP_ATTR_MAX + 1] = {
Alexander Duyck2f90b862008-11-20 20:52:10 -080075 [DCB_PFC_UP_ATTR_0] = {.type = NLA_U8},
76 [DCB_PFC_UP_ATTR_1] = {.type = NLA_U8},
77 [DCB_PFC_UP_ATTR_2] = {.type = NLA_U8},
78 [DCB_PFC_UP_ATTR_3] = {.type = NLA_U8},
79 [DCB_PFC_UP_ATTR_4] = {.type = NLA_U8},
80 [DCB_PFC_UP_ATTR_5] = {.type = NLA_U8},
81 [DCB_PFC_UP_ATTR_6] = {.type = NLA_U8},
82 [DCB_PFC_UP_ATTR_7] = {.type = NLA_U8},
83 [DCB_PFC_UP_ATTR_ALL] = {.type = NLA_FLAG},
84};
85
86/* DCB priority grouping nested attributes */
Alexey Dobriyanb54452b2010-02-18 08:14:31 +000087static const struct nla_policy dcbnl_pg_nest[DCB_PG_ATTR_MAX + 1] = {
Alexander Duyck2f90b862008-11-20 20:52:10 -080088 [DCB_PG_ATTR_TC_0] = {.type = NLA_NESTED},
89 [DCB_PG_ATTR_TC_1] = {.type = NLA_NESTED},
90 [DCB_PG_ATTR_TC_2] = {.type = NLA_NESTED},
91 [DCB_PG_ATTR_TC_3] = {.type = NLA_NESTED},
92 [DCB_PG_ATTR_TC_4] = {.type = NLA_NESTED},
93 [DCB_PG_ATTR_TC_5] = {.type = NLA_NESTED},
94 [DCB_PG_ATTR_TC_6] = {.type = NLA_NESTED},
95 [DCB_PG_ATTR_TC_7] = {.type = NLA_NESTED},
96 [DCB_PG_ATTR_TC_ALL] = {.type = NLA_NESTED},
97 [DCB_PG_ATTR_BW_ID_0] = {.type = NLA_U8},
98 [DCB_PG_ATTR_BW_ID_1] = {.type = NLA_U8},
99 [DCB_PG_ATTR_BW_ID_2] = {.type = NLA_U8},
100 [DCB_PG_ATTR_BW_ID_3] = {.type = NLA_U8},
101 [DCB_PG_ATTR_BW_ID_4] = {.type = NLA_U8},
102 [DCB_PG_ATTR_BW_ID_5] = {.type = NLA_U8},
103 [DCB_PG_ATTR_BW_ID_6] = {.type = NLA_U8},
104 [DCB_PG_ATTR_BW_ID_7] = {.type = NLA_U8},
105 [DCB_PG_ATTR_BW_ID_ALL] = {.type = NLA_FLAG},
106};
107
108/* DCB traffic class nested attributes. */
Alexey Dobriyanb54452b2010-02-18 08:14:31 +0000109static const struct nla_policy dcbnl_tc_param_nest[DCB_TC_ATTR_PARAM_MAX + 1] = {
Alexander Duyck2f90b862008-11-20 20:52:10 -0800110 [DCB_TC_ATTR_PARAM_PGID] = {.type = NLA_U8},
111 [DCB_TC_ATTR_PARAM_UP_MAPPING] = {.type = NLA_U8},
112 [DCB_TC_ATTR_PARAM_STRICT_PRIO] = {.type = NLA_U8},
113 [DCB_TC_ATTR_PARAM_BW_PCT] = {.type = NLA_U8},
114 [DCB_TC_ATTR_PARAM_ALL] = {.type = NLA_FLAG},
115};
116
Alexander Duyck46132182008-11-20 21:05:08 -0800117/* DCB capabilities nested attributes. */
Alexey Dobriyanb54452b2010-02-18 08:14:31 +0000118static const struct nla_policy dcbnl_cap_nest[DCB_CAP_ATTR_MAX + 1] = {
Alexander Duyck46132182008-11-20 21:05:08 -0800119 [DCB_CAP_ATTR_ALL] = {.type = NLA_FLAG},
120 [DCB_CAP_ATTR_PG] = {.type = NLA_U8},
121 [DCB_CAP_ATTR_PFC] = {.type = NLA_U8},
122 [DCB_CAP_ATTR_UP2TC] = {.type = NLA_U8},
123 [DCB_CAP_ATTR_PG_TCS] = {.type = NLA_U8},
124 [DCB_CAP_ATTR_PFC_TCS] = {.type = NLA_U8},
125 [DCB_CAP_ATTR_GSP] = {.type = NLA_U8},
126 [DCB_CAP_ATTR_BCN] = {.type = NLA_U8},
127};
Alexander Duyck2f90b862008-11-20 20:52:10 -0800128
Alexander Duyck33dbabc2008-11-20 21:08:19 -0800129/* DCB capabilities nested attributes. */
Alexey Dobriyanb54452b2010-02-18 08:14:31 +0000130static const struct nla_policy dcbnl_numtcs_nest[DCB_NUMTCS_ATTR_MAX + 1] = {
Alexander Duyck33dbabc2008-11-20 21:08:19 -0800131 [DCB_NUMTCS_ATTR_ALL] = {.type = NLA_FLAG},
132 [DCB_NUMTCS_ATTR_PG] = {.type = NLA_U8},
133 [DCB_NUMTCS_ATTR_PFC] = {.type = NLA_U8},
134};
135
Alexander Duyck859ee3c2008-11-20 21:10:23 -0800136/* DCB BCN nested attributes. */
Alexey Dobriyanb54452b2010-02-18 08:14:31 +0000137static const struct nla_policy dcbnl_bcn_nest[DCB_BCN_ATTR_MAX + 1] = {
Alexander Duyck859ee3c2008-11-20 21:10:23 -0800138 [DCB_BCN_ATTR_RP_0] = {.type = NLA_U8},
139 [DCB_BCN_ATTR_RP_1] = {.type = NLA_U8},
140 [DCB_BCN_ATTR_RP_2] = {.type = NLA_U8},
141 [DCB_BCN_ATTR_RP_3] = {.type = NLA_U8},
142 [DCB_BCN_ATTR_RP_4] = {.type = NLA_U8},
143 [DCB_BCN_ATTR_RP_5] = {.type = NLA_U8},
144 [DCB_BCN_ATTR_RP_6] = {.type = NLA_U8},
145 [DCB_BCN_ATTR_RP_7] = {.type = NLA_U8},
146 [DCB_BCN_ATTR_RP_ALL] = {.type = NLA_FLAG},
Don Skidmoref4314e82008-12-21 20:10:29 -0800147 [DCB_BCN_ATTR_BCNA_0] = {.type = NLA_U32},
148 [DCB_BCN_ATTR_BCNA_1] = {.type = NLA_U32},
Alexander Duyck859ee3c2008-11-20 21:10:23 -0800149 [DCB_BCN_ATTR_ALPHA] = {.type = NLA_U32},
150 [DCB_BCN_ATTR_BETA] = {.type = NLA_U32},
151 [DCB_BCN_ATTR_GD] = {.type = NLA_U32},
152 [DCB_BCN_ATTR_GI] = {.type = NLA_U32},
153 [DCB_BCN_ATTR_TMAX] = {.type = NLA_U32},
154 [DCB_BCN_ATTR_TD] = {.type = NLA_U32},
155 [DCB_BCN_ATTR_RMIN] = {.type = NLA_U32},
156 [DCB_BCN_ATTR_W] = {.type = NLA_U32},
157 [DCB_BCN_ATTR_RD] = {.type = NLA_U32},
158 [DCB_BCN_ATTR_RU] = {.type = NLA_U32},
159 [DCB_BCN_ATTR_WRTT] = {.type = NLA_U32},
160 [DCB_BCN_ATTR_RI] = {.type = NLA_U32},
161 [DCB_BCN_ATTR_C] = {.type = NLA_U32},
162 [DCB_BCN_ATTR_ALL] = {.type = NLA_FLAG},
163};
164
Yi Zou6fa382a2009-08-31 12:33:20 +0000165/* DCB APP nested attributes. */
Alexey Dobriyanb54452b2010-02-18 08:14:31 +0000166static const struct nla_policy dcbnl_app_nest[DCB_APP_ATTR_MAX + 1] = {
Yi Zou6fa382a2009-08-31 12:33:20 +0000167 [DCB_APP_ATTR_IDTYPE] = {.type = NLA_U8},
168 [DCB_APP_ATTR_ID] = {.type = NLA_U16},
169 [DCB_APP_ATTR_PRIORITY] = {.type = NLA_U8},
170};
171
John Fastabend3e290272010-12-30 09:25:46 +0000172/* IEEE 802.1Qaz nested attributes. */
173static const struct nla_policy dcbnl_ieee_policy[DCB_ATTR_IEEE_MAX + 1] = {
174 [DCB_ATTR_IEEE_ETS] = {.len = sizeof(struct ieee_ets)},
175 [DCB_ATTR_IEEE_PFC] = {.len = sizeof(struct ieee_pfc)},
176 [DCB_ATTR_IEEE_APP_TABLE] = {.type = NLA_NESTED},
177};
178
179static const struct nla_policy dcbnl_ieee_app[DCB_ATTR_IEEE_APP_MAX + 1] = {
180 [DCB_ATTR_IEEE_APP] = {.len = sizeof(struct dcb_app)},
181};
182
John Fastabend9ab933a2010-12-30 09:26:31 +0000183static LIST_HEAD(dcb_app_list);
184static DEFINE_SPINLOCK(dcb_lock);
185
Alexander Duyck2f90b862008-11-20 20:52:10 -0800186/* standard netlink reply call */
187static int dcbnl_reply(u8 value, u8 event, u8 cmd, u8 attr, u32 pid,
188 u32 seq, u16 flags)
189{
190 struct sk_buff *dcbnl_skb;
191 struct dcbmsg *dcb;
192 struct nlmsghdr *nlh;
193 int ret = -EINVAL;
194
195 dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
196 if (!dcbnl_skb)
197 return ret;
198
199 nlh = NLMSG_NEW(dcbnl_skb, pid, seq, event, sizeof(*dcb), flags);
200
201 dcb = NLMSG_DATA(nlh);
202 dcb->dcb_family = AF_UNSPEC;
203 dcb->cmd = cmd;
204 dcb->dcb_pad = 0;
205
206 ret = nla_put_u8(dcbnl_skb, attr, value);
207 if (ret)
208 goto err;
209
210 /* end the message, assign the nlmsg_len. */
211 nlmsg_end(dcbnl_skb, nlh);
212 ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
213 if (ret)
John Fastabend7eaf5072009-09-25 13:12:03 +0000214 return -EINVAL;
Alexander Duyck2f90b862008-11-20 20:52:10 -0800215
216 return 0;
217nlmsg_failure:
218err:
Roel Kluin858eb712009-01-04 17:29:21 -0800219 kfree_skb(dcbnl_skb);
Alexander Duyck2f90b862008-11-20 20:52:10 -0800220 return ret;
221}
222
223static int dcbnl_getstate(struct net_device *netdev, struct nlattr **tb,
224 u32 pid, u32 seq, u16 flags)
225{
226 int ret = -EINVAL;
227
228 /* if (!tb[DCB_ATTR_STATE] || !netdev->dcbnl_ops->getstate) */
229 if (!netdev->dcbnl_ops->getstate)
230 return ret;
231
232 ret = dcbnl_reply(netdev->dcbnl_ops->getstate(netdev), RTM_GETDCB,
233 DCB_CMD_GSTATE, DCB_ATTR_STATE, pid, seq, flags);
234
235 return ret;
236}
237
238static int dcbnl_getpfccfg(struct net_device *netdev, struct nlattr **tb,
239 u32 pid, u32 seq, u16 flags)
240{
241 struct sk_buff *dcbnl_skb;
242 struct nlmsghdr *nlh;
243 struct dcbmsg *dcb;
244 struct nlattr *data[DCB_PFC_UP_ATTR_MAX + 1], *nest;
245 u8 value;
246 int ret = -EINVAL;
247 int i;
248 int getall = 0;
249
250 if (!tb[DCB_ATTR_PFC_CFG] || !netdev->dcbnl_ops->getpfccfg)
251 return ret;
252
253 ret = nla_parse_nested(data, DCB_PFC_UP_ATTR_MAX,
254 tb[DCB_ATTR_PFC_CFG],
255 dcbnl_pfc_up_nest);
256 if (ret)
257 goto err_out;
258
259 dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
260 if (!dcbnl_skb)
261 goto err_out;
262
263 nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
264
265 dcb = NLMSG_DATA(nlh);
266 dcb->dcb_family = AF_UNSPEC;
267 dcb->cmd = DCB_CMD_PFC_GCFG;
268
269 nest = nla_nest_start(dcbnl_skb, DCB_ATTR_PFC_CFG);
270 if (!nest)
271 goto err;
272
273 if (data[DCB_PFC_UP_ATTR_ALL])
274 getall = 1;
275
276 for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) {
277 if (!getall && !data[i])
278 continue;
279
280 netdev->dcbnl_ops->getpfccfg(netdev, i - DCB_PFC_UP_ATTR_0,
281 &value);
282 ret = nla_put_u8(dcbnl_skb, i, value);
283
284 if (ret) {
285 nla_nest_cancel(dcbnl_skb, nest);
286 goto err;
287 }
288 }
289 nla_nest_end(dcbnl_skb, nest);
290
291 nlmsg_end(dcbnl_skb, nlh);
292
293 ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
294 if (ret)
John Fastabend7eaf5072009-09-25 13:12:03 +0000295 goto err_out;
Alexander Duyck2f90b862008-11-20 20:52:10 -0800296
297 return 0;
298nlmsg_failure:
299err:
Roel Kluin858eb712009-01-04 17:29:21 -0800300 kfree_skb(dcbnl_skb);
Alexander Duyck2f90b862008-11-20 20:52:10 -0800301err_out:
302 return -EINVAL;
303}
304
305static int dcbnl_getperm_hwaddr(struct net_device *netdev, struct nlattr **tb,
306 u32 pid, u32 seq, u16 flags)
307{
308 struct sk_buff *dcbnl_skb;
309 struct nlmsghdr *nlh;
310 struct dcbmsg *dcb;
311 u8 perm_addr[MAX_ADDR_LEN];
312 int ret = -EINVAL;
313
314 if (!netdev->dcbnl_ops->getpermhwaddr)
315 return ret;
316
317 dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
318 if (!dcbnl_skb)
319 goto err_out;
320
321 nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
322
323 dcb = NLMSG_DATA(nlh);
324 dcb->dcb_family = AF_UNSPEC;
325 dcb->cmd = DCB_CMD_GPERM_HWADDR;
326
327 netdev->dcbnl_ops->getpermhwaddr(netdev, perm_addr);
328
329 ret = nla_put(dcbnl_skb, DCB_ATTR_PERM_HWADDR, sizeof(perm_addr),
330 perm_addr);
331
332 nlmsg_end(dcbnl_skb, nlh);
333
334 ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
335 if (ret)
John Fastabend7eaf5072009-09-25 13:12:03 +0000336 goto err_out;
Alexander Duyck2f90b862008-11-20 20:52:10 -0800337
338 return 0;
339
340nlmsg_failure:
Roel Kluin858eb712009-01-04 17:29:21 -0800341 kfree_skb(dcbnl_skb);
Alexander Duyck2f90b862008-11-20 20:52:10 -0800342err_out:
343 return -EINVAL;
344}
345
Alexander Duyck46132182008-11-20 21:05:08 -0800346static int dcbnl_getcap(struct net_device *netdev, struct nlattr **tb,
347 u32 pid, u32 seq, u16 flags)
348{
349 struct sk_buff *dcbnl_skb;
350 struct nlmsghdr *nlh;
351 struct dcbmsg *dcb;
352 struct nlattr *data[DCB_CAP_ATTR_MAX + 1], *nest;
353 u8 value;
354 int ret = -EINVAL;
355 int i;
356 int getall = 0;
357
358 if (!tb[DCB_ATTR_CAP] || !netdev->dcbnl_ops->getcap)
359 return ret;
360
361 ret = nla_parse_nested(data, DCB_CAP_ATTR_MAX, tb[DCB_ATTR_CAP],
362 dcbnl_cap_nest);
363 if (ret)
364 goto err_out;
365
366 dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
367 if (!dcbnl_skb)
368 goto err_out;
369
370 nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
371
372 dcb = NLMSG_DATA(nlh);
373 dcb->dcb_family = AF_UNSPEC;
374 dcb->cmd = DCB_CMD_GCAP;
375
376 nest = nla_nest_start(dcbnl_skb, DCB_ATTR_CAP);
377 if (!nest)
378 goto err;
379
380 if (data[DCB_CAP_ATTR_ALL])
381 getall = 1;
382
383 for (i = DCB_CAP_ATTR_ALL+1; i <= DCB_CAP_ATTR_MAX; i++) {
384 if (!getall && !data[i])
385 continue;
386
387 if (!netdev->dcbnl_ops->getcap(netdev, i, &value)) {
388 ret = nla_put_u8(dcbnl_skb, i, value);
389
390 if (ret) {
391 nla_nest_cancel(dcbnl_skb, nest);
392 goto err;
393 }
394 }
395 }
396 nla_nest_end(dcbnl_skb, nest);
397
398 nlmsg_end(dcbnl_skb, nlh);
399
400 ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
401 if (ret)
John Fastabend7eaf5072009-09-25 13:12:03 +0000402 goto err_out;
Alexander Duyck46132182008-11-20 21:05:08 -0800403
404 return 0;
405nlmsg_failure:
406err:
Roel Kluin858eb712009-01-04 17:29:21 -0800407 kfree_skb(dcbnl_skb);
Alexander Duyck46132182008-11-20 21:05:08 -0800408err_out:
409 return -EINVAL;
410}
411
Alexander Duyck33dbabc2008-11-20 21:08:19 -0800412static int dcbnl_getnumtcs(struct net_device *netdev, struct nlattr **tb,
413 u32 pid, u32 seq, u16 flags)
414{
415 struct sk_buff *dcbnl_skb;
416 struct nlmsghdr *nlh;
417 struct dcbmsg *dcb;
418 struct nlattr *data[DCB_NUMTCS_ATTR_MAX + 1], *nest;
419 u8 value;
420 int ret = -EINVAL;
421 int i;
422 int getall = 0;
423
424 if (!tb[DCB_ATTR_NUMTCS] || !netdev->dcbnl_ops->getnumtcs)
425 return ret;
426
427 ret = nla_parse_nested(data, DCB_NUMTCS_ATTR_MAX, tb[DCB_ATTR_NUMTCS],
428 dcbnl_numtcs_nest);
429 if (ret) {
430 ret = -EINVAL;
431 goto err_out;
432 }
433
434 dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
435 if (!dcbnl_skb) {
436 ret = -EINVAL;
437 goto err_out;
438 }
439
440 nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
441
442 dcb = NLMSG_DATA(nlh);
443 dcb->dcb_family = AF_UNSPEC;
444 dcb->cmd = DCB_CMD_GNUMTCS;
445
446 nest = nla_nest_start(dcbnl_skb, DCB_ATTR_NUMTCS);
447 if (!nest) {
448 ret = -EINVAL;
449 goto err;
450 }
451
452 if (data[DCB_NUMTCS_ATTR_ALL])
453 getall = 1;
454
455 for (i = DCB_NUMTCS_ATTR_ALL+1; i <= DCB_NUMTCS_ATTR_MAX; i++) {
456 if (!getall && !data[i])
457 continue;
458
459 ret = netdev->dcbnl_ops->getnumtcs(netdev, i, &value);
460 if (!ret) {
461 ret = nla_put_u8(dcbnl_skb, i, value);
462
463 if (ret) {
464 nla_nest_cancel(dcbnl_skb, nest);
465 ret = -EINVAL;
466 goto err;
467 }
468 } else {
469 goto err;
470 }
471 }
472 nla_nest_end(dcbnl_skb, nest);
473
474 nlmsg_end(dcbnl_skb, nlh);
475
476 ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
477 if (ret) {
478 ret = -EINVAL;
John Fastabend7eaf5072009-09-25 13:12:03 +0000479 goto err_out;
Alexander Duyck33dbabc2008-11-20 21:08:19 -0800480 }
481
482 return 0;
483nlmsg_failure:
484err:
Roel Kluin858eb712009-01-04 17:29:21 -0800485 kfree_skb(dcbnl_skb);
Alexander Duyck33dbabc2008-11-20 21:08:19 -0800486err_out:
487 return ret;
488}
489
490static int dcbnl_setnumtcs(struct net_device *netdev, struct nlattr **tb,
491 u32 pid, u32 seq, u16 flags)
492{
493 struct nlattr *data[DCB_NUMTCS_ATTR_MAX + 1];
494 int ret = -EINVAL;
495 u8 value;
496 int i;
497
Don Skidmore8b124a82008-12-15 01:06:23 -0800498 if (!tb[DCB_ATTR_NUMTCS] || !netdev->dcbnl_ops->setnumtcs)
Alexander Duyck33dbabc2008-11-20 21:08:19 -0800499 return ret;
500
501 ret = nla_parse_nested(data, DCB_NUMTCS_ATTR_MAX, tb[DCB_ATTR_NUMTCS],
502 dcbnl_numtcs_nest);
503
504 if (ret) {
505 ret = -EINVAL;
506 goto err;
507 }
508
509 for (i = DCB_NUMTCS_ATTR_ALL+1; i <= DCB_NUMTCS_ATTR_MAX; i++) {
510 if (data[i] == NULL)
511 continue;
512
513 value = nla_get_u8(data[i]);
514
515 ret = netdev->dcbnl_ops->setnumtcs(netdev, i, value);
516
517 if (ret)
518 goto operr;
519 }
520
521operr:
522 ret = dcbnl_reply(!!ret, RTM_SETDCB, DCB_CMD_SNUMTCS,
523 DCB_ATTR_NUMTCS, pid, seq, flags);
524
525err:
526 return ret;
527}
528
Alexander Duyck0eb3aa92008-11-20 21:09:23 -0800529static int dcbnl_getpfcstate(struct net_device *netdev, struct nlattr **tb,
530 u32 pid, u32 seq, u16 flags)
531{
532 int ret = -EINVAL;
533
534 if (!netdev->dcbnl_ops->getpfcstate)
535 return ret;
536
537 ret = dcbnl_reply(netdev->dcbnl_ops->getpfcstate(netdev), RTM_GETDCB,
538 DCB_CMD_PFC_GSTATE, DCB_ATTR_PFC_STATE,
539 pid, seq, flags);
540
541 return ret;
542}
543
544static int dcbnl_setpfcstate(struct net_device *netdev, struct nlattr **tb,
545 u32 pid, u32 seq, u16 flags)
546{
547 int ret = -EINVAL;
548 u8 value;
549
550 if (!tb[DCB_ATTR_PFC_STATE] || !netdev->dcbnl_ops->setpfcstate)
551 return ret;
552
553 value = nla_get_u8(tb[DCB_ATTR_PFC_STATE]);
554
555 netdev->dcbnl_ops->setpfcstate(netdev, value);
556
557 ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_PFC_SSTATE, DCB_ATTR_PFC_STATE,
558 pid, seq, flags);
559
560 return ret;
561}
562
Yi Zou57949682009-08-31 12:33:40 +0000563static int dcbnl_getapp(struct net_device *netdev, struct nlattr **tb,
564 u32 pid, u32 seq, u16 flags)
565{
566 struct sk_buff *dcbnl_skb;
567 struct nlmsghdr *nlh;
568 struct dcbmsg *dcb;
569 struct nlattr *app_nest;
570 struct nlattr *app_tb[DCB_APP_ATTR_MAX + 1];
571 u16 id;
572 u8 up, idtype;
573 int ret = -EINVAL;
574
575 if (!tb[DCB_ATTR_APP] || !netdev->dcbnl_ops->getapp)
576 goto out;
577
578 ret = nla_parse_nested(app_tb, DCB_APP_ATTR_MAX, tb[DCB_ATTR_APP],
579 dcbnl_app_nest);
580 if (ret)
581 goto out;
582
583 ret = -EINVAL;
584 /* all must be non-null */
585 if ((!app_tb[DCB_APP_ATTR_IDTYPE]) ||
586 (!app_tb[DCB_APP_ATTR_ID]))
587 goto out;
588
589 /* either by eth type or by socket number */
590 idtype = nla_get_u8(app_tb[DCB_APP_ATTR_IDTYPE]);
591 if ((idtype != DCB_APP_IDTYPE_ETHTYPE) &&
592 (idtype != DCB_APP_IDTYPE_PORTNUM))
593 goto out;
594
595 id = nla_get_u16(app_tb[DCB_APP_ATTR_ID]);
596 up = netdev->dcbnl_ops->getapp(netdev, idtype, id);
597
598 /* send this back */
599 dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
600 if (!dcbnl_skb)
601 goto out;
602
603 nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
604 dcb = NLMSG_DATA(nlh);
605 dcb->dcb_family = AF_UNSPEC;
606 dcb->cmd = DCB_CMD_GAPP;
607
608 app_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_APP);
609 ret = nla_put_u8(dcbnl_skb, DCB_APP_ATTR_IDTYPE, idtype);
610 if (ret)
611 goto out_cancel;
612
613 ret = nla_put_u16(dcbnl_skb, DCB_APP_ATTR_ID, id);
614 if (ret)
615 goto out_cancel;
616
617 ret = nla_put_u8(dcbnl_skb, DCB_APP_ATTR_PRIORITY, up);
618 if (ret)
619 goto out_cancel;
620
621 nla_nest_end(dcbnl_skb, app_nest);
622 nlmsg_end(dcbnl_skb, nlh);
623
624 ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
625 if (ret)
626 goto nlmsg_failure;
627
628 goto out;
629
630out_cancel:
631 nla_nest_cancel(dcbnl_skb, app_nest);
632nlmsg_failure:
633 kfree_skb(dcbnl_skb);
634out:
635 return ret;
636}
637
638static int dcbnl_setapp(struct net_device *netdev, struct nlattr **tb,
639 u32 pid, u32 seq, u16 flags)
640{
John Fastabend9ab933a2010-12-30 09:26:31 +0000641 int err, ret = -EINVAL;
Yi Zou57949682009-08-31 12:33:40 +0000642 u16 id;
643 u8 up, idtype;
644 struct nlattr *app_tb[DCB_APP_ATTR_MAX + 1];
645
John Fastabend9ab933a2010-12-30 09:26:31 +0000646 if (!tb[DCB_ATTR_APP])
Yi Zou57949682009-08-31 12:33:40 +0000647 goto out;
648
649 ret = nla_parse_nested(app_tb, DCB_APP_ATTR_MAX, tb[DCB_ATTR_APP],
650 dcbnl_app_nest);
651 if (ret)
652 goto out;
653
654 ret = -EINVAL;
655 /* all must be non-null */
656 if ((!app_tb[DCB_APP_ATTR_IDTYPE]) ||
657 (!app_tb[DCB_APP_ATTR_ID]) ||
658 (!app_tb[DCB_APP_ATTR_PRIORITY]))
659 goto out;
660
661 /* either by eth type or by socket number */
662 idtype = nla_get_u8(app_tb[DCB_APP_ATTR_IDTYPE]);
663 if ((idtype != DCB_APP_IDTYPE_ETHTYPE) &&
664 (idtype != DCB_APP_IDTYPE_PORTNUM))
665 goto out;
666
667 id = nla_get_u16(app_tb[DCB_APP_ATTR_ID]);
668 up = nla_get_u8(app_tb[DCB_APP_ATTR_PRIORITY]);
669
John Fastabend9ab933a2010-12-30 09:26:31 +0000670 if (netdev->dcbnl_ops->setapp) {
671 err = netdev->dcbnl_ops->setapp(netdev, idtype, id, up);
672 } else {
673 struct dcb_app app;
674 app.selector = idtype;
675 app.protocol = id;
676 app.priority = up;
677 err = dcb_setapp(netdev, &app);
678 }
679
680 ret = dcbnl_reply(err, RTM_SETDCB, DCB_CMD_SAPP, DCB_ATTR_APP,
681 pid, seq, flags);
Yi Zou57949682009-08-31 12:33:40 +0000682out:
683 return ret;
684}
685
Alexander Duyck2f90b862008-11-20 20:52:10 -0800686static int __dcbnl_pg_getcfg(struct net_device *netdev, struct nlattr **tb,
687 u32 pid, u32 seq, u16 flags, int dir)
688{
689 struct sk_buff *dcbnl_skb;
690 struct nlmsghdr *nlh;
691 struct dcbmsg *dcb;
692 struct nlattr *pg_nest, *param_nest, *data;
693 struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1];
694 struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1];
695 u8 prio, pgid, tc_pct, up_map;
696 int ret = -EINVAL;
697 int getall = 0;
698 int i;
699
700 if (!tb[DCB_ATTR_PG_CFG] ||
701 !netdev->dcbnl_ops->getpgtccfgtx ||
702 !netdev->dcbnl_ops->getpgtccfgrx ||
703 !netdev->dcbnl_ops->getpgbwgcfgtx ||
704 !netdev->dcbnl_ops->getpgbwgcfgrx)
705 return ret;
706
707 ret = nla_parse_nested(pg_tb, DCB_PG_ATTR_MAX,
708 tb[DCB_ATTR_PG_CFG], dcbnl_pg_nest);
709
710 if (ret)
711 goto err_out;
712
713 dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
714 if (!dcbnl_skb)
715 goto err_out;
716
717 nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
718
719 dcb = NLMSG_DATA(nlh);
720 dcb->dcb_family = AF_UNSPEC;
721 dcb->cmd = (dir) ? DCB_CMD_PGRX_GCFG : DCB_CMD_PGTX_GCFG;
722
723 pg_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_PG_CFG);
724 if (!pg_nest)
725 goto err;
726
727 if (pg_tb[DCB_PG_ATTR_TC_ALL])
728 getall = 1;
729
730 for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) {
731 if (!getall && !pg_tb[i])
732 continue;
733
734 if (pg_tb[DCB_PG_ATTR_TC_ALL])
735 data = pg_tb[DCB_PG_ATTR_TC_ALL];
736 else
737 data = pg_tb[i];
738 ret = nla_parse_nested(param_tb, DCB_TC_ATTR_PARAM_MAX,
739 data, dcbnl_tc_param_nest);
740 if (ret)
741 goto err_pg;
742
743 param_nest = nla_nest_start(dcbnl_skb, i);
744 if (!param_nest)
745 goto err_pg;
746
747 pgid = DCB_ATTR_VALUE_UNDEFINED;
748 prio = DCB_ATTR_VALUE_UNDEFINED;
749 tc_pct = DCB_ATTR_VALUE_UNDEFINED;
750 up_map = DCB_ATTR_VALUE_UNDEFINED;
751
752 if (dir) {
753 /* Rx */
754 netdev->dcbnl_ops->getpgtccfgrx(netdev,
755 i - DCB_PG_ATTR_TC_0, &prio,
756 &pgid, &tc_pct, &up_map);
757 } else {
758 /* Tx */
759 netdev->dcbnl_ops->getpgtccfgtx(netdev,
760 i - DCB_PG_ATTR_TC_0, &prio,
761 &pgid, &tc_pct, &up_map);
762 }
763
764 if (param_tb[DCB_TC_ATTR_PARAM_PGID] ||
765 param_tb[DCB_TC_ATTR_PARAM_ALL]) {
766 ret = nla_put_u8(dcbnl_skb,
767 DCB_TC_ATTR_PARAM_PGID, pgid);
768 if (ret)
769 goto err_param;
770 }
771 if (param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING] ||
772 param_tb[DCB_TC_ATTR_PARAM_ALL]) {
773 ret = nla_put_u8(dcbnl_skb,
774 DCB_TC_ATTR_PARAM_UP_MAPPING, up_map);
775 if (ret)
776 goto err_param;
777 }
778 if (param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO] ||
779 param_tb[DCB_TC_ATTR_PARAM_ALL]) {
780 ret = nla_put_u8(dcbnl_skb,
781 DCB_TC_ATTR_PARAM_STRICT_PRIO, prio);
782 if (ret)
783 goto err_param;
784 }
785 if (param_tb[DCB_TC_ATTR_PARAM_BW_PCT] ||
786 param_tb[DCB_TC_ATTR_PARAM_ALL]) {
787 ret = nla_put_u8(dcbnl_skb, DCB_TC_ATTR_PARAM_BW_PCT,
788 tc_pct);
789 if (ret)
790 goto err_param;
791 }
792 nla_nest_end(dcbnl_skb, param_nest);
793 }
794
795 if (pg_tb[DCB_PG_ATTR_BW_ID_ALL])
796 getall = 1;
797 else
798 getall = 0;
799
800 for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) {
801 if (!getall && !pg_tb[i])
802 continue;
803
804 tc_pct = DCB_ATTR_VALUE_UNDEFINED;
805
806 if (dir) {
807 /* Rx */
808 netdev->dcbnl_ops->getpgbwgcfgrx(netdev,
809 i - DCB_PG_ATTR_BW_ID_0, &tc_pct);
810 } else {
811 /* Tx */
812 netdev->dcbnl_ops->getpgbwgcfgtx(netdev,
813 i - DCB_PG_ATTR_BW_ID_0, &tc_pct);
814 }
815 ret = nla_put_u8(dcbnl_skb, i, tc_pct);
816
817 if (ret)
818 goto err_pg;
819 }
820
821 nla_nest_end(dcbnl_skb, pg_nest);
822
823 nlmsg_end(dcbnl_skb, nlh);
824
825 ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
826 if (ret)
John Fastabend7eaf5072009-09-25 13:12:03 +0000827 goto err_out;
Alexander Duyck2f90b862008-11-20 20:52:10 -0800828
829 return 0;
830
831err_param:
832 nla_nest_cancel(dcbnl_skb, param_nest);
833err_pg:
834 nla_nest_cancel(dcbnl_skb, pg_nest);
835nlmsg_failure:
836err:
Roel Kluin858eb712009-01-04 17:29:21 -0800837 kfree_skb(dcbnl_skb);
Alexander Duyck2f90b862008-11-20 20:52:10 -0800838err_out:
839 ret = -EINVAL;
840 return ret;
841}
842
843static int dcbnl_pgtx_getcfg(struct net_device *netdev, struct nlattr **tb,
844 u32 pid, u32 seq, u16 flags)
845{
846 return __dcbnl_pg_getcfg(netdev, tb, pid, seq, flags, 0);
847}
848
849static int dcbnl_pgrx_getcfg(struct net_device *netdev, struct nlattr **tb,
850 u32 pid, u32 seq, u16 flags)
851{
852 return __dcbnl_pg_getcfg(netdev, tb, pid, seq, flags, 1);
853}
854
855static int dcbnl_setstate(struct net_device *netdev, struct nlattr **tb,
856 u32 pid, u32 seq, u16 flags)
857{
858 int ret = -EINVAL;
859 u8 value;
860
861 if (!tb[DCB_ATTR_STATE] || !netdev->dcbnl_ops->setstate)
862 return ret;
863
864 value = nla_get_u8(tb[DCB_ATTR_STATE]);
865
Don Skidmore1486a612008-12-21 20:09:50 -0800866 ret = dcbnl_reply(netdev->dcbnl_ops->setstate(netdev, value),
867 RTM_SETDCB, DCB_CMD_SSTATE, DCB_ATTR_STATE,
Alexander Duyck2f90b862008-11-20 20:52:10 -0800868 pid, seq, flags);
869
870 return ret;
871}
872
873static int dcbnl_setpfccfg(struct net_device *netdev, struct nlattr **tb,
874 u32 pid, u32 seq, u16 flags)
875{
876 struct nlattr *data[DCB_PFC_UP_ATTR_MAX + 1];
877 int i;
878 int ret = -EINVAL;
879 u8 value;
880
881 if (!tb[DCB_ATTR_PFC_CFG] || !netdev->dcbnl_ops->setpfccfg)
882 return ret;
883
884 ret = nla_parse_nested(data, DCB_PFC_UP_ATTR_MAX,
885 tb[DCB_ATTR_PFC_CFG],
886 dcbnl_pfc_up_nest);
887 if (ret)
888 goto err;
889
890 for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) {
891 if (data[i] == NULL)
892 continue;
893 value = nla_get_u8(data[i]);
894 netdev->dcbnl_ops->setpfccfg(netdev,
895 data[i]->nla_type - DCB_PFC_UP_ATTR_0, value);
896 }
897
898 ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_PFC_SCFG, DCB_ATTR_PFC_CFG,
899 pid, seq, flags);
900err:
901 return ret;
902}
903
904static int dcbnl_setall(struct net_device *netdev, struct nlattr **tb,
905 u32 pid, u32 seq, u16 flags)
906{
907 int ret = -EINVAL;
908
909 if (!tb[DCB_ATTR_SET_ALL] || !netdev->dcbnl_ops->setall)
910 return ret;
911
912 ret = dcbnl_reply(netdev->dcbnl_ops->setall(netdev), RTM_SETDCB,
913 DCB_CMD_SET_ALL, DCB_ATTR_SET_ALL, pid, seq, flags);
914
915 return ret;
916}
917
918static int __dcbnl_pg_setcfg(struct net_device *netdev, struct nlattr **tb,
919 u32 pid, u32 seq, u16 flags, int dir)
920{
921 struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1];
922 struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1];
923 int ret = -EINVAL;
924 int i;
925 u8 pgid;
926 u8 up_map;
927 u8 prio;
928 u8 tc_pct;
929
930 if (!tb[DCB_ATTR_PG_CFG] ||
931 !netdev->dcbnl_ops->setpgtccfgtx ||
932 !netdev->dcbnl_ops->setpgtccfgrx ||
933 !netdev->dcbnl_ops->setpgbwgcfgtx ||
934 !netdev->dcbnl_ops->setpgbwgcfgrx)
935 return ret;
936
937 ret = nla_parse_nested(pg_tb, DCB_PG_ATTR_MAX,
938 tb[DCB_ATTR_PG_CFG], dcbnl_pg_nest);
939 if (ret)
940 goto err;
941
942 for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) {
943 if (!pg_tb[i])
944 continue;
945
946 ret = nla_parse_nested(param_tb, DCB_TC_ATTR_PARAM_MAX,
947 pg_tb[i], dcbnl_tc_param_nest);
948 if (ret)
949 goto err;
950
951 pgid = DCB_ATTR_VALUE_UNDEFINED;
952 prio = DCB_ATTR_VALUE_UNDEFINED;
953 tc_pct = DCB_ATTR_VALUE_UNDEFINED;
954 up_map = DCB_ATTR_VALUE_UNDEFINED;
955
956 if (param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO])
957 prio =
958 nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO]);
959
960 if (param_tb[DCB_TC_ATTR_PARAM_PGID])
961 pgid = nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_PGID]);
962
963 if (param_tb[DCB_TC_ATTR_PARAM_BW_PCT])
964 tc_pct = nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_BW_PCT]);
965
966 if (param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING])
967 up_map =
968 nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING]);
969
970 /* dir: Tx = 0, Rx = 1 */
971 if (dir) {
972 /* Rx */
973 netdev->dcbnl_ops->setpgtccfgrx(netdev,
974 i - DCB_PG_ATTR_TC_0,
975 prio, pgid, tc_pct, up_map);
976 } else {
977 /* Tx */
978 netdev->dcbnl_ops->setpgtccfgtx(netdev,
979 i - DCB_PG_ATTR_TC_0,
980 prio, pgid, tc_pct, up_map);
981 }
982 }
983
984 for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) {
985 if (!pg_tb[i])
986 continue;
987
988 tc_pct = nla_get_u8(pg_tb[i]);
989
990 /* dir: Tx = 0, Rx = 1 */
991 if (dir) {
992 /* Rx */
993 netdev->dcbnl_ops->setpgbwgcfgrx(netdev,
994 i - DCB_PG_ATTR_BW_ID_0, tc_pct);
995 } else {
996 /* Tx */
997 netdev->dcbnl_ops->setpgbwgcfgtx(netdev,
998 i - DCB_PG_ATTR_BW_ID_0, tc_pct);
999 }
1000 }
1001
1002 ret = dcbnl_reply(0, RTM_SETDCB,
1003 (dir ? DCB_CMD_PGRX_SCFG : DCB_CMD_PGTX_SCFG),
1004 DCB_ATTR_PG_CFG, pid, seq, flags);
1005
1006err:
1007 return ret;
1008}
1009
1010static int dcbnl_pgtx_setcfg(struct net_device *netdev, struct nlattr **tb,
1011 u32 pid, u32 seq, u16 flags)
1012{
1013 return __dcbnl_pg_setcfg(netdev, tb, pid, seq, flags, 0);
1014}
1015
1016static int dcbnl_pgrx_setcfg(struct net_device *netdev, struct nlattr **tb,
1017 u32 pid, u32 seq, u16 flags)
1018{
1019 return __dcbnl_pg_setcfg(netdev, tb, pid, seq, flags, 1);
1020}
1021
Alexander Duyck859ee3c2008-11-20 21:10:23 -08001022static int dcbnl_bcn_getcfg(struct net_device *netdev, struct nlattr **tb,
1023 u32 pid, u32 seq, u16 flags)
1024{
1025 struct sk_buff *dcbnl_skb;
1026 struct nlmsghdr *nlh;
1027 struct dcbmsg *dcb;
1028 struct nlattr *bcn_nest;
1029 struct nlattr *bcn_tb[DCB_BCN_ATTR_MAX + 1];
1030 u8 value_byte;
1031 u32 value_integer;
1032 int ret = -EINVAL;
1033 bool getall = false;
1034 int i;
1035
1036 if (!tb[DCB_ATTR_BCN] || !netdev->dcbnl_ops->getbcnrp ||
1037 !netdev->dcbnl_ops->getbcncfg)
1038 return ret;
1039
1040 ret = nla_parse_nested(bcn_tb, DCB_BCN_ATTR_MAX,
1041 tb[DCB_ATTR_BCN], dcbnl_bcn_nest);
1042
1043 if (ret)
1044 goto err_out;
1045
1046 dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1047 if (!dcbnl_skb)
1048 goto err_out;
1049
1050 nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
1051
1052 dcb = NLMSG_DATA(nlh);
1053 dcb->dcb_family = AF_UNSPEC;
1054 dcb->cmd = DCB_CMD_BCN_GCFG;
1055
1056 bcn_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_BCN);
1057 if (!bcn_nest)
1058 goto err;
1059
1060 if (bcn_tb[DCB_BCN_ATTR_ALL])
1061 getall = true;
1062
1063 for (i = DCB_BCN_ATTR_RP_0; i <= DCB_BCN_ATTR_RP_7; i++) {
1064 if (!getall && !bcn_tb[i])
1065 continue;
1066
1067 netdev->dcbnl_ops->getbcnrp(netdev, i - DCB_BCN_ATTR_RP_0,
1068 &value_byte);
1069 ret = nla_put_u8(dcbnl_skb, i, value_byte);
1070 if (ret)
1071 goto err_bcn;
1072 }
1073
Don Skidmoref4314e82008-12-21 20:10:29 -08001074 for (i = DCB_BCN_ATTR_BCNA_0; i <= DCB_BCN_ATTR_RI; i++) {
Alexander Duyck859ee3c2008-11-20 21:10:23 -08001075 if (!getall && !bcn_tb[i])
1076 continue;
1077
1078 netdev->dcbnl_ops->getbcncfg(netdev, i,
1079 &value_integer);
1080 ret = nla_put_u32(dcbnl_skb, i, value_integer);
1081 if (ret)
1082 goto err_bcn;
1083 }
1084
1085 nla_nest_end(dcbnl_skb, bcn_nest);
1086
1087 nlmsg_end(dcbnl_skb, nlh);
1088
1089 ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
1090 if (ret)
John Fastabend7eaf5072009-09-25 13:12:03 +00001091 goto err_out;
Alexander Duyck859ee3c2008-11-20 21:10:23 -08001092
1093 return 0;
1094
1095err_bcn:
1096 nla_nest_cancel(dcbnl_skb, bcn_nest);
1097nlmsg_failure:
1098err:
Roel Kluin858eb712009-01-04 17:29:21 -08001099 kfree_skb(dcbnl_skb);
Alexander Duyck859ee3c2008-11-20 21:10:23 -08001100err_out:
1101 ret = -EINVAL;
1102 return ret;
1103}
1104
1105static int dcbnl_bcn_setcfg(struct net_device *netdev, struct nlattr **tb,
1106 u32 pid, u32 seq, u16 flags)
1107{
1108 struct nlattr *data[DCB_BCN_ATTR_MAX + 1];
1109 int i;
1110 int ret = -EINVAL;
1111 u8 value_byte;
1112 u32 value_int;
1113
Joe Perchesf64f9e72009-11-29 16:55:45 -08001114 if (!tb[DCB_ATTR_BCN] || !netdev->dcbnl_ops->setbcncfg ||
1115 !netdev->dcbnl_ops->setbcnrp)
Alexander Duyck859ee3c2008-11-20 21:10:23 -08001116 return ret;
1117
1118 ret = nla_parse_nested(data, DCB_BCN_ATTR_MAX,
1119 tb[DCB_ATTR_BCN],
1120 dcbnl_pfc_up_nest);
1121 if (ret)
1122 goto err;
1123
1124 for (i = DCB_BCN_ATTR_RP_0; i <= DCB_BCN_ATTR_RP_7; i++) {
1125 if (data[i] == NULL)
1126 continue;
1127 value_byte = nla_get_u8(data[i]);
1128 netdev->dcbnl_ops->setbcnrp(netdev,
1129 data[i]->nla_type - DCB_BCN_ATTR_RP_0, value_byte);
1130 }
1131
Don Skidmoref4314e82008-12-21 20:10:29 -08001132 for (i = DCB_BCN_ATTR_BCNA_0; i <= DCB_BCN_ATTR_RI; i++) {
Alexander Duyck859ee3c2008-11-20 21:10:23 -08001133 if (data[i] == NULL)
1134 continue;
1135 value_int = nla_get_u32(data[i]);
1136 netdev->dcbnl_ops->setbcncfg(netdev,
1137 i, value_int);
1138 }
1139
1140 ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_BCN_SCFG, DCB_ATTR_BCN,
1141 pid, seq, flags);
1142err:
1143 return ret;
1144}
1145
John Fastabend3e290272010-12-30 09:25:46 +00001146/* Handle IEEE 802.1Qaz SET commands. If any requested operation can not
1147 * be completed the entire msg is aborted and error value is returned.
1148 * No attempt is made to reconcile the case where only part of the
1149 * cmd can be completed.
1150 */
1151static int dcbnl_ieee_set(struct net_device *netdev, struct nlattr **tb,
1152 u32 pid, u32 seq, u16 flags)
1153{
1154 const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
1155 struct nlattr *ieee[DCB_ATTR_IEEE_MAX + 1];
1156 int err = -EOPNOTSUPP;
1157
1158 if (!ops)
1159 goto err;
1160
1161 err = nla_parse_nested(ieee, DCB_ATTR_IEEE_MAX,
1162 tb[DCB_ATTR_IEEE], dcbnl_ieee_policy);
1163 if (err)
1164 goto err;
1165
1166 if (ieee[DCB_ATTR_IEEE_ETS] && ops->ieee_setets) {
1167 struct ieee_ets *ets = nla_data(ieee[DCB_ATTR_IEEE_ETS]);
1168 err = ops->ieee_setets(netdev, ets);
1169 if (err)
1170 goto err;
1171 }
1172
1173 if (ieee[DCB_ATTR_IEEE_PFC] && ops->ieee_setets) {
1174 struct ieee_pfc *pfc = nla_data(ieee[DCB_ATTR_IEEE_PFC]);
1175 err = ops->ieee_setpfc(netdev, pfc);
1176 if (err)
1177 goto err;
1178 }
1179
John Fastabend9ab933a2010-12-30 09:26:31 +00001180 if (ieee[DCB_ATTR_IEEE_APP_TABLE]) {
John Fastabend3e290272010-12-30 09:25:46 +00001181 struct nlattr *attr;
1182 int rem;
1183
1184 nla_for_each_nested(attr, ieee[DCB_ATTR_IEEE_APP_TABLE], rem) {
1185 struct dcb_app *app_data;
1186 if (nla_type(attr) != DCB_ATTR_IEEE_APP)
1187 continue;
1188 app_data = nla_data(attr);
John Fastabend9ab933a2010-12-30 09:26:31 +00001189 if (ops->ieee_setapp)
1190 err = ops->ieee_setapp(netdev, app_data);
1191 else
1192 err = dcb_setapp(netdev, app_data);
John Fastabend3e290272010-12-30 09:25:46 +00001193 if (err)
1194 goto err;
1195 }
1196 }
1197
1198err:
1199 dcbnl_reply(err, RTM_SETDCB, DCB_CMD_IEEE_SET, DCB_ATTR_IEEE,
1200 pid, seq, flags);
1201 return err;
1202}
1203
1204
1205/* Handle IEEE 802.1Qaz GET commands. */
1206static int dcbnl_ieee_get(struct net_device *netdev, struct nlattr **tb,
1207 u32 pid, u32 seq, u16 flags)
1208{
1209 struct sk_buff *skb;
1210 struct nlmsghdr *nlh;
1211 struct dcbmsg *dcb;
John Fastabend9ab933a2010-12-30 09:26:31 +00001212 struct nlattr *ieee, *app;
1213 struct dcb_app_type *itr;
John Fastabend3e290272010-12-30 09:25:46 +00001214 const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
1215 int err;
1216
1217 if (!ops)
1218 return -EOPNOTSUPP;
1219
1220 skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1221 if (!skb)
1222 return -ENOBUFS;
1223
1224 nlh = NLMSG_NEW(skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
1225
1226 dcb = NLMSG_DATA(nlh);
1227 dcb->dcb_family = AF_UNSPEC;
1228 dcb->cmd = DCB_CMD_IEEE_GET;
1229
1230 NLA_PUT_STRING(skb, DCB_ATTR_IFNAME, netdev->name);
1231
1232 ieee = nla_nest_start(skb, DCB_ATTR_IEEE);
1233 if (!ieee)
1234 goto nla_put_failure;
1235
1236 if (ops->ieee_getets) {
1237 struct ieee_ets ets;
1238 err = ops->ieee_getets(netdev, &ets);
1239 if (!err)
1240 NLA_PUT(skb, DCB_ATTR_IEEE_ETS, sizeof(ets), &ets);
1241 }
1242
1243 if (ops->ieee_getpfc) {
1244 struct ieee_pfc pfc;
1245 err = ops->ieee_getpfc(netdev, &pfc);
1246 if (!err)
1247 NLA_PUT(skb, DCB_ATTR_IEEE_PFC, sizeof(pfc), &pfc);
1248 }
1249
John Fastabend9ab933a2010-12-30 09:26:31 +00001250 app = nla_nest_start(skb, DCB_ATTR_IEEE_APP_TABLE);
1251 if (!app)
1252 goto nla_put_failure;
1253
1254 spin_lock(&dcb_lock);
1255 list_for_each_entry(itr, &dcb_app_list, list) {
1256 if (strncmp(itr->name, netdev->name, IFNAMSIZ) == 0)
1257 NLA_PUT(skb, DCB_ATTR_IEEE_APP,
1258 sizeof(itr->app), &itr->app);
1259 }
1260 spin_unlock(&dcb_lock);
1261 nla_nest_end(skb, app);
1262
John Fastabend3e290272010-12-30 09:25:46 +00001263 nla_nest_end(skb, ieee);
1264 nlmsg_end(skb, nlh);
1265
1266 return rtnl_unicast(skb, &init_net, pid);
1267nla_put_failure:
1268 nlmsg_cancel(skb, nlh);
1269nlmsg_failure:
1270 kfree_skb(skb);
1271 return -1;
1272}
1273
Alexander Duyck2f90b862008-11-20 20:52:10 -08001274static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
1275{
1276 struct net *net = sock_net(skb->sk);
1277 struct net_device *netdev;
1278 struct dcbmsg *dcb = (struct dcbmsg *)NLMSG_DATA(nlh);
1279 struct nlattr *tb[DCB_ATTR_MAX + 1];
1280 u32 pid = skb ? NETLINK_CB(skb).pid : 0;
1281 int ret = -EINVAL;
1282
Octavian Purdila09ad9bc2009-11-25 15:14:13 -08001283 if (!net_eq(net, &init_net))
Alexander Duyck2f90b862008-11-20 20:52:10 -08001284 return -EINVAL;
1285
1286 ret = nlmsg_parse(nlh, sizeof(*dcb), tb, DCB_ATTR_MAX,
1287 dcbnl_rtnl_policy);
1288 if (ret < 0)
1289 return ret;
1290
1291 if (!tb[DCB_ATTR_IFNAME])
1292 return -EINVAL;
1293
1294 netdev = dev_get_by_name(&init_net, nla_data(tb[DCB_ATTR_IFNAME]));
1295 if (!netdev)
1296 return -EINVAL;
1297
1298 if (!netdev->dcbnl_ops)
1299 goto errout;
1300
1301 switch (dcb->cmd) {
1302 case DCB_CMD_GSTATE:
1303 ret = dcbnl_getstate(netdev, tb, pid, nlh->nlmsg_seq,
1304 nlh->nlmsg_flags);
1305 goto out;
1306 case DCB_CMD_PFC_GCFG:
1307 ret = dcbnl_getpfccfg(netdev, tb, pid, nlh->nlmsg_seq,
1308 nlh->nlmsg_flags);
1309 goto out;
1310 case DCB_CMD_GPERM_HWADDR:
1311 ret = dcbnl_getperm_hwaddr(netdev, tb, pid, nlh->nlmsg_seq,
1312 nlh->nlmsg_flags);
1313 goto out;
1314 case DCB_CMD_PGTX_GCFG:
1315 ret = dcbnl_pgtx_getcfg(netdev, tb, pid, nlh->nlmsg_seq,
1316 nlh->nlmsg_flags);
1317 goto out;
1318 case DCB_CMD_PGRX_GCFG:
1319 ret = dcbnl_pgrx_getcfg(netdev, tb, pid, nlh->nlmsg_seq,
1320 nlh->nlmsg_flags);
1321 goto out;
Alexander Duyck859ee3c2008-11-20 21:10:23 -08001322 case DCB_CMD_BCN_GCFG:
1323 ret = dcbnl_bcn_getcfg(netdev, tb, pid, nlh->nlmsg_seq,
1324 nlh->nlmsg_flags);
1325 goto out;
Alexander Duyck2f90b862008-11-20 20:52:10 -08001326 case DCB_CMD_SSTATE:
1327 ret = dcbnl_setstate(netdev, tb, pid, nlh->nlmsg_seq,
1328 nlh->nlmsg_flags);
1329 goto out;
1330 case DCB_CMD_PFC_SCFG:
1331 ret = dcbnl_setpfccfg(netdev, tb, pid, nlh->nlmsg_seq,
1332 nlh->nlmsg_flags);
1333 goto out;
1334
1335 case DCB_CMD_SET_ALL:
1336 ret = dcbnl_setall(netdev, tb, pid, nlh->nlmsg_seq,
1337 nlh->nlmsg_flags);
1338 goto out;
1339 case DCB_CMD_PGTX_SCFG:
1340 ret = dcbnl_pgtx_setcfg(netdev, tb, pid, nlh->nlmsg_seq,
1341 nlh->nlmsg_flags);
1342 goto out;
1343 case DCB_CMD_PGRX_SCFG:
1344 ret = dcbnl_pgrx_setcfg(netdev, tb, pid, nlh->nlmsg_seq,
1345 nlh->nlmsg_flags);
1346 goto out;
Alexander Duyck46132182008-11-20 21:05:08 -08001347 case DCB_CMD_GCAP:
1348 ret = dcbnl_getcap(netdev, tb, pid, nlh->nlmsg_seq,
1349 nlh->nlmsg_flags);
1350 goto out;
Alexander Duyck33dbabc2008-11-20 21:08:19 -08001351 case DCB_CMD_GNUMTCS:
1352 ret = dcbnl_getnumtcs(netdev, tb, pid, nlh->nlmsg_seq,
1353 nlh->nlmsg_flags);
1354 goto out;
1355 case DCB_CMD_SNUMTCS:
1356 ret = dcbnl_setnumtcs(netdev, tb, pid, nlh->nlmsg_seq,
1357 nlh->nlmsg_flags);
1358 goto out;
Alexander Duyck0eb3aa92008-11-20 21:09:23 -08001359 case DCB_CMD_PFC_GSTATE:
1360 ret = dcbnl_getpfcstate(netdev, tb, pid, nlh->nlmsg_seq,
1361 nlh->nlmsg_flags);
1362 goto out;
1363 case DCB_CMD_PFC_SSTATE:
1364 ret = dcbnl_setpfcstate(netdev, tb, pid, nlh->nlmsg_seq,
1365 nlh->nlmsg_flags);
1366 goto out;
Alexander Duyck859ee3c2008-11-20 21:10:23 -08001367 case DCB_CMD_BCN_SCFG:
1368 ret = dcbnl_bcn_setcfg(netdev, tb, pid, nlh->nlmsg_seq,
1369 nlh->nlmsg_flags);
1370 goto out;
Yi Zou57949682009-08-31 12:33:40 +00001371 case DCB_CMD_GAPP:
1372 ret = dcbnl_getapp(netdev, tb, pid, nlh->nlmsg_seq,
1373 nlh->nlmsg_flags);
1374 goto out;
1375 case DCB_CMD_SAPP:
1376 ret = dcbnl_setapp(netdev, tb, pid, nlh->nlmsg_seq,
1377 nlh->nlmsg_flags);
1378 goto out;
John Fastabend3e290272010-12-30 09:25:46 +00001379 case DCB_CMD_IEEE_SET:
1380 ret = dcbnl_ieee_set(netdev, tb, pid, nlh->nlmsg_seq,
1381 nlh->nlmsg_flags);
1382 goto out;
1383 case DCB_CMD_IEEE_GET:
1384 ret = dcbnl_ieee_get(netdev, tb, pid, nlh->nlmsg_seq,
1385 nlh->nlmsg_flags);
1386 goto out;
Alexander Duyck2f90b862008-11-20 20:52:10 -08001387 default:
1388 goto errout;
1389 }
1390errout:
1391 ret = -EINVAL;
1392out:
1393 dev_put(netdev);
1394 return ret;
1395}
1396
John Fastabend9ab933a2010-12-30 09:26:31 +00001397/**
1398 * dcb_getapp - retrieve the DCBX application user priority
1399 *
1400 * On success returns a non-zero 802.1p user priority bitmap
1401 * otherwise returns 0 as the invalid user priority bitmap to
1402 * indicate an error.
1403 */
1404u8 dcb_getapp(struct net_device *dev, struct dcb_app *app)
1405{
1406 struct dcb_app_type *itr;
1407 u8 prio = 0;
1408
1409 spin_lock(&dcb_lock);
1410 list_for_each_entry(itr, &dcb_app_list, list) {
1411 if (itr->app.selector == app->selector &&
1412 itr->app.protocol == app->protocol &&
1413 (strncmp(itr->name, dev->name, IFNAMSIZ) == 0)) {
1414 prio = itr->app.priority;
1415 break;
1416 }
1417 }
1418 spin_unlock(&dcb_lock);
1419
1420 return prio;
1421}
1422EXPORT_SYMBOL(dcb_getapp);
1423
1424/**
1425 * ixgbe_dcbnl_setapp - add dcb application data to app list
1426 *
1427 * Priority 0 is the default priority this removes applications
1428 * from the app list if the priority is set to zero.
1429 */
1430u8 dcb_setapp(struct net_device *dev, struct dcb_app *new)
1431{
1432 struct dcb_app_type *itr;
1433
1434 spin_lock(&dcb_lock);
1435 /* Search for existing match and replace */
1436 list_for_each_entry(itr, &dcb_app_list, list) {
1437 if (itr->app.selector == new->selector &&
1438 itr->app.protocol == new->protocol &&
1439 (strncmp(itr->name, dev->name, IFNAMSIZ) == 0)) {
1440 if (new->priority)
1441 itr->app.priority = new->priority;
1442 else {
1443 list_del(&itr->list);
1444 kfree(itr);
1445 }
1446 goto out;
1447 }
1448 }
1449 /* App type does not exist add new application type */
1450 if (new->priority) {
1451 struct dcb_app_type *entry;
1452 entry = kmalloc(sizeof(struct dcb_app_type), GFP_ATOMIC);
1453 if (!entry) {
1454 spin_unlock(&dcb_lock);
1455 return -ENOMEM;
1456 }
1457
1458 memcpy(&entry->app, new, sizeof(*new));
1459 strncpy(entry->name, dev->name, IFNAMSIZ);
1460 list_add(&entry->list, &dcb_app_list);
1461 }
1462out:
1463 spin_unlock(&dcb_lock);
John Fastabend96b99682010-12-30 09:26:37 +00001464 call_dcbevent_notifiers(DCB_APP_EVENT, new);
John Fastabend9ab933a2010-12-30 09:26:31 +00001465 return 0;
1466}
1467EXPORT_SYMBOL(dcb_setapp);
1468
1469void dcb_flushapp(void)
1470{
1471 struct dcb_app_type *app;
1472
1473 spin_lock(&dcb_lock);
1474 list_for_each_entry(app, &dcb_app_list, list) {
1475 list_del(&app->list);
1476 kfree(app);
1477 }
1478 spin_unlock(&dcb_lock);
1479}
1480
Alexander Duyck2f90b862008-11-20 20:52:10 -08001481static int __init dcbnl_init(void)
1482{
John Fastabend9ab933a2010-12-30 09:26:31 +00001483 INIT_LIST_HEAD(&dcb_app_list);
1484
Alexander Duyck2f90b862008-11-20 20:52:10 -08001485 rtnl_register(PF_UNSPEC, RTM_GETDCB, dcb_doit, NULL);
1486 rtnl_register(PF_UNSPEC, RTM_SETDCB, dcb_doit, NULL);
1487
1488 return 0;
1489}
1490module_init(dcbnl_init);
1491
1492static void __exit dcbnl_exit(void)
1493{
1494 rtnl_unregister(PF_UNSPEC, RTM_GETDCB);
1495 rtnl_unregister(PF_UNSPEC, RTM_SETDCB);
John Fastabend9ab933a2010-12-30 09:26:31 +00001496 dcb_flushapp();
Alexander Duyck2f90b862008-11-20 20:52:10 -08001497}
1498module_exit(dcbnl_exit);