ixgbe: this patch adds support for DCB to the kernel and ixgbe driver
[linux-2.6.git] / net / dcb / dcbnl.c
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
50 MODULE_AUTHOR("Lucy Liu, <lucy.liu@intel.com>");
51 MODULE_DESCRIPTION("Data Center Bridging generic netlink interface");
52 MODULE_LICENSE("GPL");
53
54 /**************** DCB attribute policies *************************************/
55
56 /* DCB netlink attributes policy */
57 static 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 */
67 static 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 */
80 static 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. */
102 static 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 */
112 static 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;
142 nlmsg_failure:
143 err:
144         kfree(dcbnl_skb);
145         return ret;
146 }
147
148 static 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
163 static 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;
223 nlmsg_failure:
224 err:
225         kfree(dcbnl_skb);
226 err_out:
227         return -EINVAL;
228 }
229
230 static 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
265 nlmsg_failure:
266 err:
267         kfree(dcbnl_skb);
268 err_out:
269         return -EINVAL;
270 }
271
272 static 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
417 err_param:
418         nla_nest_cancel(dcbnl_skb, param_nest);
419 err_pg:
420         nla_nest_cancel(dcbnl_skb, pg_nest);
421 nlmsg_failure:
422 err:
423         kfree(dcbnl_skb);
424 err_out:
425         ret  = -EINVAL;
426         return ret;
427 }
428
429 static 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
435 static 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
441 static 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
460 static 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);
487 err:
488         return ret;
489 }
490
491 static 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
505 static 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
593 err:
594         return ret;
595 }
596
597 static 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
603 static 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
609 static 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         }
681 errout:
682         ret = -EINVAL;
683 out:
684         dev_put(netdev);
685         return ret;
686 }
687
688 static 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 }
695 module_init(dcbnl_init);
696
697 static void __exit dcbnl_exit(void)
698 {
699         rtnl_unregister(PF_UNSPEC, RTM_GETDCB);
700         rtnl_unregister(PF_UNSPEC, RTM_SETDCB);
701 }
702 module_exit(dcbnl_exit);
703
704