aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorAlexander Duyck <alexander.h.duyck@intel.com>2008-11-20 23:52:10 -0500
committerDavid S. Miller <davem@davemloft.net>2008-11-20 23:52:10 -0500
commit2f90b8657ec942d1880f720e0177ee71df7c8e3c (patch)
tree844114b22c548fedbab67e53b09b2efcf170563a /net
parent9db66bdcc83749affe61c61eb8ff3cf08f42afec (diff)
ixgbe: this patch adds support for DCB to the kernel and ixgbe driver
This adds support for Data Center Bridging (DCB) features in the ixgbe driver and adds an rtnetlink interface for configuring DCB to the kernel. The DCB feature support included are Priority Grouping (PG) - which allows bandwidth guarantees to be allocated to groups to traffic based on the 802.1q priority, and Priority Based Flow Control (PFC) - which introduces a new MAC control PAUSE frame which works at granularity of the 802.1p priority instead of the link (IEEE 802.3x). Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com> Signed-off-by: Peter P Waskiewicz Jr <peter.p.waskiewicz.jr@intel.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/Kconfig1
-rw-r--r--net/Makefile3
-rw-r--r--net/dcb/Kconfig12
-rw-r--r--net/dcb/Makefile1
-rw-r--r--net/dcb/dcbnl.c704
5 files changed, 721 insertions, 0 deletions
diff --git a/net/Kconfig b/net/Kconfig
index 4e2e40ba8ba6..c7d01c3a23c5 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -194,6 +194,7 @@ source "net/lapb/Kconfig"
194source "net/econet/Kconfig" 194source "net/econet/Kconfig"
195source "net/wanrouter/Kconfig" 195source "net/wanrouter/Kconfig"
196source "net/sched/Kconfig" 196source "net/sched/Kconfig"
197source "net/dcb/Kconfig"
197 198
198menu "Network testing" 199menu "Network testing"
199 200
diff --git a/net/Makefile b/net/Makefile
index 27d1f10dc0e0..83b064651f1d 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -57,6 +57,9 @@ obj-$(CONFIG_NETLABEL) += netlabel/
57obj-$(CONFIG_IUCV) += iucv/ 57obj-$(CONFIG_IUCV) += iucv/
58obj-$(CONFIG_RFKILL) += rfkill/ 58obj-$(CONFIG_RFKILL) += rfkill/
59obj-$(CONFIG_NET_9P) += 9p/ 59obj-$(CONFIG_NET_9P) += 9p/
60ifeq ($(CONFIG_DCBNL),y)
61obj-$(CONFIG_DCB) += dcb/
62endif
60 63
61ifeq ($(CONFIG_NET),y) 64ifeq ($(CONFIG_NET),y)
62obj-$(CONFIG_SYSCTL) += sysctl_net.o 65obj-$(CONFIG_SYSCTL) += sysctl_net.o
diff --git a/net/dcb/Kconfig b/net/dcb/Kconfig
new file mode 100644
index 000000000000..bdf38802d339
--- /dev/null
+++ b/net/dcb/Kconfig
@@ -0,0 +1,12 @@
1config DCB
2 tristate "Data Center Bridging support"
3
4config DCBNL
5 bool "Data Center Bridging netlink interface support"
6 depends on DCB
7 default n
8 ---help---
9 This option turns on the netlink interface
10 (dcbnl) for Data Center Bridging capable devices.
11
12 If unsure, say N.
diff --git a/net/dcb/Makefile b/net/dcb/Makefile
new file mode 100644
index 000000000000..9930f4cde818
--- /dev/null
+++ b/net/dcb/Makefile
@@ -0,0 +1 @@
obj-$(CONFIG_DCB) += dcbnl.o
diff --git a/net/dcb/dcbnl.c b/net/dcb/dcbnl.c
new file mode 100644
index 000000000000..516e8be83d72
--- /dev/null
+++ b/net/dcb/dcbnl.c
@@ -0,0 +1,704 @@
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
20#include <linux/netdevice.h>
21#include <linux/netlink.h>
22#include <net/netlink.h>
23#include <net/rtnetlink.h>
24#include <linux/dcbnl.h>
25#include <linux/rtnetlink.h>
26#include <net/sock.h>
27
28/**
29 * Data Center Bridging (DCB) is a collection of Ethernet enhancements
30 * intended to allow network traffic with differing requirements
31 * (highly reliable, no drops vs. best effort vs. low latency) to operate
32 * and co-exist on Ethernet. Current DCB features are:
33 *
34 * Enhanced Transmission Selection (aka Priority Grouping [PG]) - provides a
35 * framework for assigning bandwidth guarantees to traffic classes.
36 *
37 * Priority-based Flow Control (PFC) - provides a flow control mechanism which
38 * can work independently for each 802.1p priority.
39 *
40 * Congestion Notification - provides a mechanism for end-to-end congestion
41 * control for protocols which do not have built-in congestion management.
42 *
43 * More information about the emerging standards for these Ethernet features
44 * can be found at: http://www.ieee802.org/1/pages/dcbridges.html
45 *
46 * This file implements an rtnetlink interface to allow configuration of DCB
47 * features for capable devices.
48 */
49
50MODULE_AUTHOR("Lucy Liu, <lucy.liu@intel.com>");
51MODULE_DESCRIPTION("Data Center Bridging generic netlink interface");
52MODULE_LICENSE("GPL");
53
54/**************** DCB attribute policies *************************************/
55
56/* DCB netlink attributes policy */
57static struct nla_policy dcbnl_rtnl_policy[DCB_ATTR_MAX + 1] = {
58 [DCB_ATTR_IFNAME] = {.type = NLA_STRING, .len = IFNAMSIZ - 1},
59 [DCB_ATTR_STATE] = {.type = NLA_U8},
60 [DCB_ATTR_PFC_CFG] = {.type = NLA_NESTED},
61 [DCB_ATTR_PG_CFG] = {.type = NLA_NESTED},
62 [DCB_ATTR_SET_ALL] = {.type = NLA_U8},
63 [DCB_ATTR_PERM_HWADDR] = {.type = NLA_FLAG},
64};
65
66/* DCB priority flow control to User Priority nested attributes */
67static struct nla_policy dcbnl_pfc_up_nest[DCB_PFC_UP_ATTR_MAX + 1] = {
68 [DCB_PFC_UP_ATTR_0] = {.type = NLA_U8},
69 [DCB_PFC_UP_ATTR_1] = {.type = NLA_U8},
70 [DCB_PFC_UP_ATTR_2] = {.type = NLA_U8},
71 [DCB_PFC_UP_ATTR_3] = {.type = NLA_U8},
72 [DCB_PFC_UP_ATTR_4] = {.type = NLA_U8},
73 [DCB_PFC_UP_ATTR_5] = {.type = NLA_U8},
74 [DCB_PFC_UP_ATTR_6] = {.type = NLA_U8},
75 [DCB_PFC_UP_ATTR_7] = {.type = NLA_U8},
76 [DCB_PFC_UP_ATTR_ALL] = {.type = NLA_FLAG},
77};
78
79/* DCB priority grouping nested attributes */
80static struct nla_policy dcbnl_pg_nest[DCB_PG_ATTR_MAX + 1] = {
81 [DCB_PG_ATTR_TC_0] = {.type = NLA_NESTED},
82 [DCB_PG_ATTR_TC_1] = {.type = NLA_NESTED},
83 [DCB_PG_ATTR_TC_2] = {.type = NLA_NESTED},
84 [DCB_PG_ATTR_TC_3] = {.type = NLA_NESTED},
85 [DCB_PG_ATTR_TC_4] = {.type = NLA_NESTED},
86 [DCB_PG_ATTR_TC_5] = {.type = NLA_NESTED},
87 [DCB_PG_ATTR_TC_6] = {.type = NLA_NESTED},
88 [DCB_PG_ATTR_TC_7] = {.type = NLA_NESTED},
89 [DCB_PG_ATTR_TC_ALL] = {.type = NLA_NESTED},
90 [DCB_PG_ATTR_BW_ID_0] = {.type = NLA_U8},
91 [DCB_PG_ATTR_BW_ID_1] = {.type = NLA_U8},
92 [DCB_PG_ATTR_BW_ID_2] = {.type = NLA_U8},
93 [DCB_PG_ATTR_BW_ID_3] = {.type = NLA_U8},
94 [DCB_PG_ATTR_BW_ID_4] = {.type = NLA_U8},
95 [DCB_PG_ATTR_BW_ID_5] = {.type = NLA_U8},
96 [DCB_PG_ATTR_BW_ID_6] = {.type = NLA_U8},
97 [DCB_PG_ATTR_BW_ID_7] = {.type = NLA_U8},
98 [DCB_PG_ATTR_BW_ID_ALL] = {.type = NLA_FLAG},
99};
100
101/* DCB traffic class nested attributes. */
102static struct nla_policy dcbnl_tc_param_nest[DCB_TC_ATTR_PARAM_MAX + 1] = {
103 [DCB_TC_ATTR_PARAM_PGID] = {.type = NLA_U8},
104 [DCB_TC_ATTR_PARAM_UP_MAPPING] = {.type = NLA_U8},
105 [DCB_TC_ATTR_PARAM_STRICT_PRIO] = {.type = NLA_U8},
106 [DCB_TC_ATTR_PARAM_BW_PCT] = {.type = NLA_U8},
107 [DCB_TC_ATTR_PARAM_ALL] = {.type = NLA_FLAG},
108};
109
110
111/* standard netlink reply call */
112static int dcbnl_reply(u8 value, u8 event, u8 cmd, u8 attr, u32 pid,
113 u32 seq, u16 flags)
114{
115 struct sk_buff *dcbnl_skb;
116 struct dcbmsg *dcb;
117 struct nlmsghdr *nlh;
118 int ret = -EINVAL;
119
120 dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
121 if (!dcbnl_skb)
122 return ret;
123
124 nlh = NLMSG_NEW(dcbnl_skb, pid, seq, event, sizeof(*dcb), flags);
125
126 dcb = NLMSG_DATA(nlh);
127 dcb->dcb_family = AF_UNSPEC;
128 dcb->cmd = cmd;
129 dcb->dcb_pad = 0;
130
131 ret = nla_put_u8(dcbnl_skb, attr, value);
132 if (ret)
133 goto err;
134
135 /* end the message, assign the nlmsg_len. */
136 nlmsg_end(dcbnl_skb, nlh);
137 ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
138 if (ret)
139 goto err;
140
141 return 0;
142nlmsg_failure:
143err:
144 kfree(dcbnl_skb);
145 return ret;
146}
147
148static int dcbnl_getstate(struct net_device *netdev, struct nlattr **tb,
149 u32 pid, u32 seq, u16 flags)
150{
151 int ret = -EINVAL;
152
153 /* if (!tb[DCB_ATTR_STATE] || !netdev->dcbnl_ops->getstate) */
154 if (!netdev->dcbnl_ops->getstate)
155 return ret;
156
157 ret = dcbnl_reply(netdev->dcbnl_ops->getstate(netdev), RTM_GETDCB,
158 DCB_CMD_GSTATE, DCB_ATTR_STATE, pid, seq, flags);
159
160 return ret;
161}
162
163static int dcbnl_getpfccfg(struct net_device *netdev, struct nlattr **tb,
164 u32 pid, u32 seq, u16 flags)
165{
166 struct sk_buff *dcbnl_skb;
167 struct nlmsghdr *nlh;
168 struct dcbmsg *dcb;
169 struct nlattr *data[DCB_PFC_UP_ATTR_MAX + 1], *nest;
170 u8 value;
171 int ret = -EINVAL;
172 int i;
173 int getall = 0;
174
175 if (!tb[DCB_ATTR_PFC_CFG] || !netdev->dcbnl_ops->getpfccfg)
176 return ret;
177
178 ret = nla_parse_nested(data, DCB_PFC_UP_ATTR_MAX,
179 tb[DCB_ATTR_PFC_CFG],
180 dcbnl_pfc_up_nest);
181 if (ret)
182 goto err_out;
183
184 dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
185 if (!dcbnl_skb)
186 goto err_out;
187
188 nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
189
190 dcb = NLMSG_DATA(nlh);
191 dcb->dcb_family = AF_UNSPEC;
192 dcb->cmd = DCB_CMD_PFC_GCFG;
193
194 nest = nla_nest_start(dcbnl_skb, DCB_ATTR_PFC_CFG);
195 if (!nest)
196 goto err;
197
198 if (data[DCB_PFC_UP_ATTR_ALL])
199 getall = 1;
200
201 for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) {
202 if (!getall && !data[i])
203 continue;
204
205 netdev->dcbnl_ops->getpfccfg(netdev, i - DCB_PFC_UP_ATTR_0,
206 &value);
207 ret = nla_put_u8(dcbnl_skb, i, value);
208
209 if (ret) {
210 nla_nest_cancel(dcbnl_skb, nest);
211 goto err;
212 }
213 }
214 nla_nest_end(dcbnl_skb, nest);
215
216 nlmsg_end(dcbnl_skb, nlh);
217
218 ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
219 if (ret)
220 goto err;
221
222 return 0;
223nlmsg_failure:
224err:
225 kfree(dcbnl_skb);
226err_out:
227 return -EINVAL;
228}
229
230static int dcbnl_getperm_hwaddr(struct net_device *netdev, struct nlattr **tb,
231 u32 pid, u32 seq, u16 flags)
232{
233 struct sk_buff *dcbnl_skb;
234 struct nlmsghdr *nlh;
235 struct dcbmsg *dcb;
236 u8 perm_addr[MAX_ADDR_LEN];
237 int ret = -EINVAL;
238
239 if (!netdev->dcbnl_ops->getpermhwaddr)
240 return ret;
241
242 dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
243 if (!dcbnl_skb)
244 goto err_out;
245
246 nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
247
248 dcb = NLMSG_DATA(nlh);
249 dcb->dcb_family = AF_UNSPEC;
250 dcb->cmd = DCB_CMD_GPERM_HWADDR;
251
252 netdev->dcbnl_ops->getpermhwaddr(netdev, perm_addr);
253
254 ret = nla_put(dcbnl_skb, DCB_ATTR_PERM_HWADDR, sizeof(perm_addr),
255 perm_addr);
256
257 nlmsg_end(dcbnl_skb, nlh);
258
259 ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
260 if (ret)
261 goto err;
262
263 return 0;
264
265nlmsg_failure:
266err:
267 kfree(dcbnl_skb);
268err_out:
269 return -EINVAL;
270}
271
272static int __dcbnl_pg_getcfg(struct net_device *netdev, struct nlattr **tb,
273 u32 pid, u32 seq, u16 flags, int dir)
274{
275 struct sk_buff *dcbnl_skb;
276 struct nlmsghdr *nlh;
277 struct dcbmsg *dcb;
278 struct nlattr *pg_nest, *param_nest, *data;
279 struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1];
280 struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1];
281 u8 prio, pgid, tc_pct, up_map;
282 int ret = -EINVAL;
283 int getall = 0;
284 int i;
285
286 if (!tb[DCB_ATTR_PG_CFG] ||
287 !netdev->dcbnl_ops->getpgtccfgtx ||
288 !netdev->dcbnl_ops->getpgtccfgrx ||
289 !netdev->dcbnl_ops->getpgbwgcfgtx ||
290 !netdev->dcbnl_ops->getpgbwgcfgrx)
291 return ret;
292
293 ret = nla_parse_nested(pg_tb, DCB_PG_ATTR_MAX,
294 tb[DCB_ATTR_PG_CFG], dcbnl_pg_nest);
295
296 if (ret)
297 goto err_out;
298
299 dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
300 if (!dcbnl_skb)
301 goto err_out;
302
303 nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
304
305 dcb = NLMSG_DATA(nlh);
306 dcb->dcb_family = AF_UNSPEC;
307 dcb->cmd = (dir) ? DCB_CMD_PGRX_GCFG : DCB_CMD_PGTX_GCFG;
308
309 pg_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_PG_CFG);
310 if (!pg_nest)
311 goto err;
312
313 if (pg_tb[DCB_PG_ATTR_TC_ALL])
314 getall = 1;
315
316 for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) {
317 if (!getall && !pg_tb[i])
318 continue;
319
320 if (pg_tb[DCB_PG_ATTR_TC_ALL])
321 data = pg_tb[DCB_PG_ATTR_TC_ALL];
322 else
323 data = pg_tb[i];
324 ret = nla_parse_nested(param_tb, DCB_TC_ATTR_PARAM_MAX,
325 data, dcbnl_tc_param_nest);
326 if (ret)
327 goto err_pg;
328
329 param_nest = nla_nest_start(dcbnl_skb, i);
330 if (!param_nest)
331 goto err_pg;
332
333 pgid = DCB_ATTR_VALUE_UNDEFINED;
334 prio = DCB_ATTR_VALUE_UNDEFINED;
335 tc_pct = DCB_ATTR_VALUE_UNDEFINED;
336 up_map = DCB_ATTR_VALUE_UNDEFINED;
337
338 if (dir) {
339 /* Rx */
340 netdev->dcbnl_ops->getpgtccfgrx(netdev,
341 i - DCB_PG_ATTR_TC_0, &prio,
342 &pgid, &tc_pct, &up_map);
343 } else {
344 /* Tx */
345 netdev->dcbnl_ops->getpgtccfgtx(netdev,
346 i - DCB_PG_ATTR_TC_0, &prio,
347 &pgid, &tc_pct, &up_map);
348 }
349
350 if (param_tb[DCB_TC_ATTR_PARAM_PGID] ||
351 param_tb[DCB_TC_ATTR_PARAM_ALL]) {
352 ret = nla_put_u8(dcbnl_skb,
353 DCB_TC_ATTR_PARAM_PGID, pgid);
354 if (ret)
355 goto err_param;
356 }
357 if (param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING] ||
358 param_tb[DCB_TC_ATTR_PARAM_ALL]) {
359 ret = nla_put_u8(dcbnl_skb,
360 DCB_TC_ATTR_PARAM_UP_MAPPING, up_map);
361 if (ret)
362 goto err_param;
363 }
364 if (param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO] ||
365 param_tb[DCB_TC_ATTR_PARAM_ALL]) {
366 ret = nla_put_u8(dcbnl_skb,
367 DCB_TC_ATTR_PARAM_STRICT_PRIO, prio);
368 if (ret)
369 goto err_param;
370 }
371 if (param_tb[DCB_TC_ATTR_PARAM_BW_PCT] ||
372 param_tb[DCB_TC_ATTR_PARAM_ALL]) {
373 ret = nla_put_u8(dcbnl_skb, DCB_TC_ATTR_PARAM_BW_PCT,
374 tc_pct);
375 if (ret)
376 goto err_param;
377 }
378 nla_nest_end(dcbnl_skb, param_nest);
379 }
380
381 if (pg_tb[DCB_PG_ATTR_BW_ID_ALL])
382 getall = 1;
383 else
384 getall = 0;
385
386 for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) {
387 if (!getall && !pg_tb[i])
388 continue;
389
390 tc_pct = DCB_ATTR_VALUE_UNDEFINED;
391
392 if (dir) {
393 /* Rx */
394 netdev->dcbnl_ops->getpgbwgcfgrx(netdev,
395 i - DCB_PG_ATTR_BW_ID_0, &tc_pct);
396 } else {
397 /* Tx */
398 netdev->dcbnl_ops->getpgbwgcfgtx(netdev,
399 i - DCB_PG_ATTR_BW_ID_0, &tc_pct);
400 }
401 ret = nla_put_u8(dcbnl_skb, i, tc_pct);
402
403 if (ret)
404 goto err_pg;
405 }
406
407 nla_nest_end(dcbnl_skb, pg_nest);
408
409 nlmsg_end(dcbnl_skb, nlh);
410
411 ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
412 if (ret)
413 goto err;
414
415 return 0;
416
417err_param:
418 nla_nest_cancel(dcbnl_skb, param_nest);
419err_pg:
420 nla_nest_cancel(dcbnl_skb, pg_nest);
421nlmsg_failure:
422err:
423 kfree(dcbnl_skb);
424err_out:
425 ret = -EINVAL;
426 return ret;
427}
428
429static int dcbnl_pgtx_getcfg(struct net_device *netdev, struct nlattr **tb,
430 u32 pid, u32 seq, u16 flags)
431{
432 return __dcbnl_pg_getcfg(netdev, tb, pid, seq, flags, 0);
433}
434
435static int dcbnl_pgrx_getcfg(struct net_device *netdev, struct nlattr **tb,
436 u32 pid, u32 seq, u16 flags)
437{
438 return __dcbnl_pg_getcfg(netdev, tb, pid, seq, flags, 1);
439}
440
441static int dcbnl_setstate(struct net_device *netdev, struct nlattr **tb,
442 u32 pid, u32 seq, u16 flags)
443{
444 int ret = -EINVAL;
445 u8 value;
446
447 if (!tb[DCB_ATTR_STATE] || !netdev->dcbnl_ops->setstate)
448 return ret;
449
450 value = nla_get_u8(tb[DCB_ATTR_STATE]);
451
452 netdev->dcbnl_ops->setstate(netdev, value);
453
454 ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_SSTATE, DCB_ATTR_STATE,
455 pid, seq, flags);
456
457 return ret;
458}
459
460static int dcbnl_setpfccfg(struct net_device *netdev, struct nlattr **tb,
461 u32 pid, u32 seq, u16 flags)
462{
463 struct nlattr *data[DCB_PFC_UP_ATTR_MAX + 1];
464 int i;
465 int ret = -EINVAL;
466 u8 value;
467
468 if (!tb[DCB_ATTR_PFC_CFG] || !netdev->dcbnl_ops->setpfccfg)
469 return ret;
470
471 ret = nla_parse_nested(data, DCB_PFC_UP_ATTR_MAX,
472 tb[DCB_ATTR_PFC_CFG],
473 dcbnl_pfc_up_nest);
474 if (ret)
475 goto err;
476
477 for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) {
478 if (data[i] == NULL)
479 continue;
480 value = nla_get_u8(data[i]);
481 netdev->dcbnl_ops->setpfccfg(netdev,
482 data[i]->nla_type - DCB_PFC_UP_ATTR_0, value);
483 }
484
485 ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_PFC_SCFG, DCB_ATTR_PFC_CFG,
486 pid, seq, flags);
487err:
488 return ret;
489}
490
491static int dcbnl_setall(struct net_device *netdev, struct nlattr **tb,
492 u32 pid, u32 seq, u16 flags)
493{
494 int ret = -EINVAL;
495
496 if (!tb[DCB_ATTR_SET_ALL] || !netdev->dcbnl_ops->setall)
497 return ret;
498
499 ret = dcbnl_reply(netdev->dcbnl_ops->setall(netdev), RTM_SETDCB,
500 DCB_CMD_SET_ALL, DCB_ATTR_SET_ALL, pid, seq, flags);
501
502 return ret;
503}
504
505static int __dcbnl_pg_setcfg(struct net_device *netdev, struct nlattr **tb,
506 u32 pid, u32 seq, u16 flags, int dir)
507{
508 struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1];
509 struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1];
510 int ret = -EINVAL;
511 int i;
512 u8 pgid;
513 u8 up_map;
514 u8 prio;
515 u8 tc_pct;
516
517 if (!tb[DCB_ATTR_PG_CFG] ||
518 !netdev->dcbnl_ops->setpgtccfgtx ||
519 !netdev->dcbnl_ops->setpgtccfgrx ||
520 !netdev->dcbnl_ops->setpgbwgcfgtx ||
521 !netdev->dcbnl_ops->setpgbwgcfgrx)
522 return ret;
523
524 ret = nla_parse_nested(pg_tb, DCB_PG_ATTR_MAX,
525 tb[DCB_ATTR_PG_CFG], dcbnl_pg_nest);
526 if (ret)
527 goto err;
528
529 for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) {
530 if (!pg_tb[i])
531 continue;
532
533 ret = nla_parse_nested(param_tb, DCB_TC_ATTR_PARAM_MAX,
534 pg_tb[i], dcbnl_tc_param_nest);
535 if (ret)
536 goto err;
537
538 pgid = DCB_ATTR_VALUE_UNDEFINED;
539 prio = DCB_ATTR_VALUE_UNDEFINED;
540 tc_pct = DCB_ATTR_VALUE_UNDEFINED;
541 up_map = DCB_ATTR_VALUE_UNDEFINED;
542
543 if (param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO])
544 prio =
545 nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO]);
546
547 if (param_tb[DCB_TC_ATTR_PARAM_PGID])
548 pgid = nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_PGID]);
549
550 if (param_tb[DCB_TC_ATTR_PARAM_BW_PCT])
551 tc_pct = nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_BW_PCT]);
552
553 if (param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING])
554 up_map =
555 nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING]);
556
557 /* dir: Tx = 0, Rx = 1 */
558 if (dir) {
559 /* Rx */
560 netdev->dcbnl_ops->setpgtccfgrx(netdev,
561 i - DCB_PG_ATTR_TC_0,
562 prio, pgid, tc_pct, up_map);
563 } else {
564 /* Tx */
565 netdev->dcbnl_ops->setpgtccfgtx(netdev,
566 i - DCB_PG_ATTR_TC_0,
567 prio, pgid, tc_pct, up_map);
568 }
569 }
570
571 for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) {
572 if (!pg_tb[i])
573 continue;
574
575 tc_pct = nla_get_u8(pg_tb[i]);
576
577 /* dir: Tx = 0, Rx = 1 */
578 if (dir) {
579 /* Rx */
580 netdev->dcbnl_ops->setpgbwgcfgrx(netdev,
581 i - DCB_PG_ATTR_BW_ID_0, tc_pct);
582 } else {
583 /* Tx */
584 netdev->dcbnl_ops->setpgbwgcfgtx(netdev,
585 i - DCB_PG_ATTR_BW_ID_0, tc_pct);
586 }
587 }
588
589 ret = dcbnl_reply(0, RTM_SETDCB,
590 (dir ? DCB_CMD_PGRX_SCFG : DCB_CMD_PGTX_SCFG),
591 DCB_ATTR_PG_CFG, pid, seq, flags);
592
593err:
594 return ret;
595}
596
597static int dcbnl_pgtx_setcfg(struct net_device *netdev, struct nlattr **tb,
598 u32 pid, u32 seq, u16 flags)
599{
600 return __dcbnl_pg_setcfg(netdev, tb, pid, seq, flags, 0);
601}
602
603static int dcbnl_pgrx_setcfg(struct net_device *netdev, struct nlattr **tb,
604 u32 pid, u32 seq, u16 flags)
605{
606 return __dcbnl_pg_setcfg(netdev, tb, pid, seq, flags, 1);
607}
608
609static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
610{
611 struct net *net = sock_net(skb->sk);
612 struct net_device *netdev;
613 struct dcbmsg *dcb = (struct dcbmsg *)NLMSG_DATA(nlh);
614 struct nlattr *tb[DCB_ATTR_MAX + 1];
615 u32 pid = skb ? NETLINK_CB(skb).pid : 0;
616 int ret = -EINVAL;
617
618 if (net != &init_net)
619 return -EINVAL;
620
621 ret = nlmsg_parse(nlh, sizeof(*dcb), tb, DCB_ATTR_MAX,
622 dcbnl_rtnl_policy);
623 if (ret < 0)
624 return ret;
625
626 if (!tb[DCB_ATTR_IFNAME])
627 return -EINVAL;
628
629 netdev = dev_get_by_name(&init_net, nla_data(tb[DCB_ATTR_IFNAME]));
630 if (!netdev)
631 return -EINVAL;
632
633 if (!netdev->dcbnl_ops)
634 goto errout;
635
636 switch (dcb->cmd) {
637 case DCB_CMD_GSTATE:
638 ret = dcbnl_getstate(netdev, tb, pid, nlh->nlmsg_seq,
639 nlh->nlmsg_flags);
640 goto out;
641 case DCB_CMD_PFC_GCFG:
642 ret = dcbnl_getpfccfg(netdev, tb, pid, nlh->nlmsg_seq,
643 nlh->nlmsg_flags);
644 goto out;
645 case DCB_CMD_GPERM_HWADDR:
646 ret = dcbnl_getperm_hwaddr(netdev, tb, pid, nlh->nlmsg_seq,
647 nlh->nlmsg_flags);
648 goto out;
649 case DCB_CMD_PGTX_GCFG:
650 ret = dcbnl_pgtx_getcfg(netdev, tb, pid, nlh->nlmsg_seq,
651 nlh->nlmsg_flags);
652 goto out;
653 case DCB_CMD_PGRX_GCFG:
654 ret = dcbnl_pgrx_getcfg(netdev, tb, pid, nlh->nlmsg_seq,
655 nlh->nlmsg_flags);
656 goto out;
657 case DCB_CMD_SSTATE:
658 ret = dcbnl_setstate(netdev, tb, pid, nlh->nlmsg_seq,
659 nlh->nlmsg_flags);
660 goto out;
661 case DCB_CMD_PFC_SCFG:
662 ret = dcbnl_setpfccfg(netdev, tb, pid, nlh->nlmsg_seq,
663 nlh->nlmsg_flags);
664 goto out;
665
666 case DCB_CMD_SET_ALL:
667 ret = dcbnl_setall(netdev, tb, pid, nlh->nlmsg_seq,
668 nlh->nlmsg_flags);
669 goto out;
670 case DCB_CMD_PGTX_SCFG:
671 ret = dcbnl_pgtx_setcfg(netdev, tb, pid, nlh->nlmsg_seq,
672 nlh->nlmsg_flags);
673 goto out;
674 case DCB_CMD_PGRX_SCFG:
675 ret = dcbnl_pgrx_setcfg(netdev, tb, pid, nlh->nlmsg_seq,
676 nlh->nlmsg_flags);
677 goto out;
678 default:
679 goto errout;
680 }
681errout:
682 ret = -EINVAL;
683out:
684 dev_put(netdev);
685 return ret;
686}
687
688static int __init dcbnl_init(void)
689{
690 rtnl_register(PF_UNSPEC, RTM_GETDCB, dcb_doit, NULL);
691 rtnl_register(PF_UNSPEC, RTM_SETDCB, dcb_doit, NULL);
692
693 return 0;
694}
695module_init(dcbnl_init);
696
697static void __exit dcbnl_exit(void)
698{
699 rtnl_unregister(PF_UNSPEC, RTM_GETDCB);
700 rtnl_unregister(PF_UNSPEC, RTM_SETDCB);
701}
702module_exit(dcbnl_exit);
703
704