2 * Copyright (c) 2008, Intel Corporation.
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.
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
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.
17 * Author: Lucy Liu <lucy.liu@intel.com>
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>
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:
34 * Enhanced Transmission Selection (aka Priority Grouping [PG]) - provides a
35 * framework for assigning bandwidth guarantees to traffic classes.
37 * Priority-based Flow Control (PFC) - provides a flow control mechanism which
38 * can work independently for each 802.1p priority.
40 * Congestion Notification - provides a mechanism for end-to-end congestion
41 * control for protocols which do not have built-in congestion management.
43 * More information about the emerging standards for these Ethernet features
44 * can be found at: http://www.ieee802.org/1/pages/dcbridges.html
46 * This file implements an rtnetlink interface to allow configuration of DCB
47 * features for capable devices.
50 MODULE_AUTHOR("Lucy Liu, <lucy.liu@intel.com>");
51 MODULE_DESCRIPTION("Data Center Bridging generic netlink interface");
52 MODULE_LICENSE("GPL");
54 /**************** DCB attribute policies *************************************/
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 [DCB_ATTR_CAP
] = {.type
= NLA_NESTED
},
65 [DCB_ATTR_PFC_STATE
] = {.type
= NLA_U8
},
68 /* DCB priority flow control to User Priority nested attributes */
69 static struct nla_policy dcbnl_pfc_up_nest
[DCB_PFC_UP_ATTR_MAX
+ 1] = {
70 [DCB_PFC_UP_ATTR_0
] = {.type
= NLA_U8
},
71 [DCB_PFC_UP_ATTR_1
] = {.type
= NLA_U8
},
72 [DCB_PFC_UP_ATTR_2
] = {.type
= NLA_U8
},
73 [DCB_PFC_UP_ATTR_3
] = {.type
= NLA_U8
},
74 [DCB_PFC_UP_ATTR_4
] = {.type
= NLA_U8
},
75 [DCB_PFC_UP_ATTR_5
] = {.type
= NLA_U8
},
76 [DCB_PFC_UP_ATTR_6
] = {.type
= NLA_U8
},
77 [DCB_PFC_UP_ATTR_7
] = {.type
= NLA_U8
},
78 [DCB_PFC_UP_ATTR_ALL
] = {.type
= NLA_FLAG
},
81 /* DCB priority grouping nested attributes */
82 static struct nla_policy dcbnl_pg_nest
[DCB_PG_ATTR_MAX
+ 1] = {
83 [DCB_PG_ATTR_TC_0
] = {.type
= NLA_NESTED
},
84 [DCB_PG_ATTR_TC_1
] = {.type
= NLA_NESTED
},
85 [DCB_PG_ATTR_TC_2
] = {.type
= NLA_NESTED
},
86 [DCB_PG_ATTR_TC_3
] = {.type
= NLA_NESTED
},
87 [DCB_PG_ATTR_TC_4
] = {.type
= NLA_NESTED
},
88 [DCB_PG_ATTR_TC_5
] = {.type
= NLA_NESTED
},
89 [DCB_PG_ATTR_TC_6
] = {.type
= NLA_NESTED
},
90 [DCB_PG_ATTR_TC_7
] = {.type
= NLA_NESTED
},
91 [DCB_PG_ATTR_TC_ALL
] = {.type
= NLA_NESTED
},
92 [DCB_PG_ATTR_BW_ID_0
] = {.type
= NLA_U8
},
93 [DCB_PG_ATTR_BW_ID_1
] = {.type
= NLA_U8
},
94 [DCB_PG_ATTR_BW_ID_2
] = {.type
= NLA_U8
},
95 [DCB_PG_ATTR_BW_ID_3
] = {.type
= NLA_U8
},
96 [DCB_PG_ATTR_BW_ID_4
] = {.type
= NLA_U8
},
97 [DCB_PG_ATTR_BW_ID_5
] = {.type
= NLA_U8
},
98 [DCB_PG_ATTR_BW_ID_6
] = {.type
= NLA_U8
},
99 [DCB_PG_ATTR_BW_ID_7
] = {.type
= NLA_U8
},
100 [DCB_PG_ATTR_BW_ID_ALL
] = {.type
= NLA_FLAG
},
103 /* DCB traffic class nested attributes. */
104 static struct nla_policy dcbnl_tc_param_nest
[DCB_TC_ATTR_PARAM_MAX
+ 1] = {
105 [DCB_TC_ATTR_PARAM_PGID
] = {.type
= NLA_U8
},
106 [DCB_TC_ATTR_PARAM_UP_MAPPING
] = {.type
= NLA_U8
},
107 [DCB_TC_ATTR_PARAM_STRICT_PRIO
] = {.type
= NLA_U8
},
108 [DCB_TC_ATTR_PARAM_BW_PCT
] = {.type
= NLA_U8
},
109 [DCB_TC_ATTR_PARAM_ALL
] = {.type
= NLA_FLAG
},
112 /* DCB capabilities nested attributes. */
113 static struct nla_policy dcbnl_cap_nest
[DCB_CAP_ATTR_MAX
+ 1] = {
114 [DCB_CAP_ATTR_ALL
] = {.type
= NLA_FLAG
},
115 [DCB_CAP_ATTR_PG
] = {.type
= NLA_U8
},
116 [DCB_CAP_ATTR_PFC
] = {.type
= NLA_U8
},
117 [DCB_CAP_ATTR_UP2TC
] = {.type
= NLA_U8
},
118 [DCB_CAP_ATTR_PG_TCS
] = {.type
= NLA_U8
},
119 [DCB_CAP_ATTR_PFC_TCS
] = {.type
= NLA_U8
},
120 [DCB_CAP_ATTR_GSP
] = {.type
= NLA_U8
},
121 [DCB_CAP_ATTR_BCN
] = {.type
= NLA_U8
},
124 /* DCB capabilities nested attributes. */
125 static struct nla_policy dcbnl_numtcs_nest
[DCB_NUMTCS_ATTR_MAX
+ 1] = {
126 [DCB_NUMTCS_ATTR_ALL
] = {.type
= NLA_FLAG
},
127 [DCB_NUMTCS_ATTR_PG
] = {.type
= NLA_U8
},
128 [DCB_NUMTCS_ATTR_PFC
] = {.type
= NLA_U8
},
131 /* standard netlink reply call */
132 static int dcbnl_reply(u8 value
, u8 event
, u8 cmd
, u8 attr
, u32 pid
,
135 struct sk_buff
*dcbnl_skb
;
137 struct nlmsghdr
*nlh
;
140 dcbnl_skb
= nlmsg_new(NLMSG_DEFAULT_SIZE
, GFP_KERNEL
);
144 nlh
= NLMSG_NEW(dcbnl_skb
, pid
, seq
, event
, sizeof(*dcb
), flags
);
146 dcb
= NLMSG_DATA(nlh
);
147 dcb
->dcb_family
= AF_UNSPEC
;
151 ret
= nla_put_u8(dcbnl_skb
, attr
, value
);
155 /* end the message, assign the nlmsg_len. */
156 nlmsg_end(dcbnl_skb
, nlh
);
157 ret
= rtnl_unicast(dcbnl_skb
, &init_net
, pid
);
168 static int dcbnl_getstate(struct net_device
*netdev
, struct nlattr
**tb
,
169 u32 pid
, u32 seq
, u16 flags
)
173 /* if (!tb[DCB_ATTR_STATE] || !netdev->dcbnl_ops->getstate) */
174 if (!netdev
->dcbnl_ops
->getstate
)
177 ret
= dcbnl_reply(netdev
->dcbnl_ops
->getstate(netdev
), RTM_GETDCB
,
178 DCB_CMD_GSTATE
, DCB_ATTR_STATE
, pid
, seq
, flags
);
183 static int dcbnl_getpfccfg(struct net_device
*netdev
, struct nlattr
**tb
,
184 u32 pid
, u32 seq
, u16 flags
)
186 struct sk_buff
*dcbnl_skb
;
187 struct nlmsghdr
*nlh
;
189 struct nlattr
*data
[DCB_PFC_UP_ATTR_MAX
+ 1], *nest
;
195 if (!tb
[DCB_ATTR_PFC_CFG
] || !netdev
->dcbnl_ops
->getpfccfg
)
198 ret
= nla_parse_nested(data
, DCB_PFC_UP_ATTR_MAX
,
199 tb
[DCB_ATTR_PFC_CFG
],
204 dcbnl_skb
= nlmsg_new(NLMSG_DEFAULT_SIZE
, GFP_KERNEL
);
208 nlh
= NLMSG_NEW(dcbnl_skb
, pid
, seq
, RTM_GETDCB
, sizeof(*dcb
), flags
);
210 dcb
= NLMSG_DATA(nlh
);
211 dcb
->dcb_family
= AF_UNSPEC
;
212 dcb
->cmd
= DCB_CMD_PFC_GCFG
;
214 nest
= nla_nest_start(dcbnl_skb
, DCB_ATTR_PFC_CFG
);
218 if (data
[DCB_PFC_UP_ATTR_ALL
])
221 for (i
= DCB_PFC_UP_ATTR_0
; i
<= DCB_PFC_UP_ATTR_7
; i
++) {
222 if (!getall
&& !data
[i
])
225 netdev
->dcbnl_ops
->getpfccfg(netdev
, i
- DCB_PFC_UP_ATTR_0
,
227 ret
= nla_put_u8(dcbnl_skb
, i
, value
);
230 nla_nest_cancel(dcbnl_skb
, nest
);
234 nla_nest_end(dcbnl_skb
, nest
);
236 nlmsg_end(dcbnl_skb
, nlh
);
238 ret
= rtnl_unicast(dcbnl_skb
, &init_net
, pid
);
250 static int dcbnl_getperm_hwaddr(struct net_device
*netdev
, struct nlattr
**tb
,
251 u32 pid
, u32 seq
, u16 flags
)
253 struct sk_buff
*dcbnl_skb
;
254 struct nlmsghdr
*nlh
;
256 u8 perm_addr
[MAX_ADDR_LEN
];
259 if (!netdev
->dcbnl_ops
->getpermhwaddr
)
262 dcbnl_skb
= nlmsg_new(NLMSG_DEFAULT_SIZE
, GFP_KERNEL
);
266 nlh
= NLMSG_NEW(dcbnl_skb
, pid
, seq
, RTM_GETDCB
, sizeof(*dcb
), flags
);
268 dcb
= NLMSG_DATA(nlh
);
269 dcb
->dcb_family
= AF_UNSPEC
;
270 dcb
->cmd
= DCB_CMD_GPERM_HWADDR
;
272 netdev
->dcbnl_ops
->getpermhwaddr(netdev
, perm_addr
);
274 ret
= nla_put(dcbnl_skb
, DCB_ATTR_PERM_HWADDR
, sizeof(perm_addr
),
277 nlmsg_end(dcbnl_skb
, nlh
);
279 ret
= rtnl_unicast(dcbnl_skb
, &init_net
, pid
);
292 static int dcbnl_getcap(struct net_device
*netdev
, struct nlattr
**tb
,
293 u32 pid
, u32 seq
, u16 flags
)
295 struct sk_buff
*dcbnl_skb
;
296 struct nlmsghdr
*nlh
;
298 struct nlattr
*data
[DCB_CAP_ATTR_MAX
+ 1], *nest
;
304 if (!tb
[DCB_ATTR_CAP
] || !netdev
->dcbnl_ops
->getcap
)
307 ret
= nla_parse_nested(data
, DCB_CAP_ATTR_MAX
, tb
[DCB_ATTR_CAP
],
312 dcbnl_skb
= nlmsg_new(NLMSG_DEFAULT_SIZE
, GFP_KERNEL
);
316 nlh
= NLMSG_NEW(dcbnl_skb
, pid
, seq
, RTM_GETDCB
, sizeof(*dcb
), flags
);
318 dcb
= NLMSG_DATA(nlh
);
319 dcb
->dcb_family
= AF_UNSPEC
;
320 dcb
->cmd
= DCB_CMD_GCAP
;
322 nest
= nla_nest_start(dcbnl_skb
, DCB_ATTR_CAP
);
326 if (data
[DCB_CAP_ATTR_ALL
])
329 for (i
= DCB_CAP_ATTR_ALL
+1; i
<= DCB_CAP_ATTR_MAX
; i
++) {
330 if (!getall
&& !data
[i
])
333 if (!netdev
->dcbnl_ops
->getcap(netdev
, i
, &value
)) {
334 ret
= nla_put_u8(dcbnl_skb
, i
, value
);
337 nla_nest_cancel(dcbnl_skb
, nest
);
342 nla_nest_end(dcbnl_skb
, nest
);
344 nlmsg_end(dcbnl_skb
, nlh
);
346 ret
= rtnl_unicast(dcbnl_skb
, &init_net
, pid
);
358 static int dcbnl_getnumtcs(struct net_device
*netdev
, struct nlattr
**tb
,
359 u32 pid
, u32 seq
, u16 flags
)
361 struct sk_buff
*dcbnl_skb
;
362 struct nlmsghdr
*nlh
;
364 struct nlattr
*data
[DCB_NUMTCS_ATTR_MAX
+ 1], *nest
;
370 if (!tb
[DCB_ATTR_NUMTCS
] || !netdev
->dcbnl_ops
->getnumtcs
)
373 ret
= nla_parse_nested(data
, DCB_NUMTCS_ATTR_MAX
, tb
[DCB_ATTR_NUMTCS
],
380 dcbnl_skb
= nlmsg_new(NLMSG_DEFAULT_SIZE
, GFP_KERNEL
);
386 nlh
= NLMSG_NEW(dcbnl_skb
, pid
, seq
, RTM_GETDCB
, sizeof(*dcb
), flags
);
388 dcb
= NLMSG_DATA(nlh
);
389 dcb
->dcb_family
= AF_UNSPEC
;
390 dcb
->cmd
= DCB_CMD_GNUMTCS
;
392 nest
= nla_nest_start(dcbnl_skb
, DCB_ATTR_NUMTCS
);
398 if (data
[DCB_NUMTCS_ATTR_ALL
])
401 for (i
= DCB_NUMTCS_ATTR_ALL
+1; i
<= DCB_NUMTCS_ATTR_MAX
; i
++) {
402 if (!getall
&& !data
[i
])
405 ret
= netdev
->dcbnl_ops
->getnumtcs(netdev
, i
, &value
);
407 ret
= nla_put_u8(dcbnl_skb
, i
, value
);
410 nla_nest_cancel(dcbnl_skb
, nest
);
418 nla_nest_end(dcbnl_skb
, nest
);
420 nlmsg_end(dcbnl_skb
, nlh
);
422 ret
= rtnl_unicast(dcbnl_skb
, &init_net
, pid
);
436 static int dcbnl_setnumtcs(struct net_device
*netdev
, struct nlattr
**tb
,
437 u32 pid
, u32 seq
, u16 flags
)
439 struct nlattr
*data
[DCB_NUMTCS_ATTR_MAX
+ 1];
444 if (!tb
[DCB_ATTR_NUMTCS
] || !netdev
->dcbnl_ops
->setstate
)
447 ret
= nla_parse_nested(data
, DCB_NUMTCS_ATTR_MAX
, tb
[DCB_ATTR_NUMTCS
],
455 for (i
= DCB_NUMTCS_ATTR_ALL
+1; i
<= DCB_NUMTCS_ATTR_MAX
; i
++) {
459 value
= nla_get_u8(data
[i
]);
461 ret
= netdev
->dcbnl_ops
->setnumtcs(netdev
, i
, value
);
468 ret
= dcbnl_reply(!!ret
, RTM_SETDCB
, DCB_CMD_SNUMTCS
,
469 DCB_ATTR_NUMTCS
, pid
, seq
, flags
);
475 static int dcbnl_getpfcstate(struct net_device
*netdev
, struct nlattr
**tb
,
476 u32 pid
, u32 seq
, u16 flags
)
480 if (!netdev
->dcbnl_ops
->getpfcstate
)
483 ret
= dcbnl_reply(netdev
->dcbnl_ops
->getpfcstate(netdev
), RTM_GETDCB
,
484 DCB_CMD_PFC_GSTATE
, DCB_ATTR_PFC_STATE
,
490 static int dcbnl_setpfcstate(struct net_device
*netdev
, struct nlattr
**tb
,
491 u32 pid
, u32 seq
, u16 flags
)
496 if (!tb
[DCB_ATTR_PFC_STATE
] || !netdev
->dcbnl_ops
->setpfcstate
)
499 value
= nla_get_u8(tb
[DCB_ATTR_PFC_STATE
]);
501 netdev
->dcbnl_ops
->setpfcstate(netdev
, value
);
503 ret
= dcbnl_reply(0, RTM_SETDCB
, DCB_CMD_PFC_SSTATE
, DCB_ATTR_PFC_STATE
,
509 static int __dcbnl_pg_getcfg(struct net_device
*netdev
, struct nlattr
**tb
,
510 u32 pid
, u32 seq
, u16 flags
, int dir
)
512 struct sk_buff
*dcbnl_skb
;
513 struct nlmsghdr
*nlh
;
515 struct nlattr
*pg_nest
, *param_nest
, *data
;
516 struct nlattr
*pg_tb
[DCB_PG_ATTR_MAX
+ 1];
517 struct nlattr
*param_tb
[DCB_TC_ATTR_PARAM_MAX
+ 1];
518 u8 prio
, pgid
, tc_pct
, up_map
;
523 if (!tb
[DCB_ATTR_PG_CFG
] ||
524 !netdev
->dcbnl_ops
->getpgtccfgtx
||
525 !netdev
->dcbnl_ops
->getpgtccfgrx
||
526 !netdev
->dcbnl_ops
->getpgbwgcfgtx
||
527 !netdev
->dcbnl_ops
->getpgbwgcfgrx
)
530 ret
= nla_parse_nested(pg_tb
, DCB_PG_ATTR_MAX
,
531 tb
[DCB_ATTR_PG_CFG
], dcbnl_pg_nest
);
536 dcbnl_skb
= nlmsg_new(NLMSG_DEFAULT_SIZE
, GFP_KERNEL
);
540 nlh
= NLMSG_NEW(dcbnl_skb
, pid
, seq
, RTM_GETDCB
, sizeof(*dcb
), flags
);
542 dcb
= NLMSG_DATA(nlh
);
543 dcb
->dcb_family
= AF_UNSPEC
;
544 dcb
->cmd
= (dir
) ? DCB_CMD_PGRX_GCFG
: DCB_CMD_PGTX_GCFG
;
546 pg_nest
= nla_nest_start(dcbnl_skb
, DCB_ATTR_PG_CFG
);
550 if (pg_tb
[DCB_PG_ATTR_TC_ALL
])
553 for (i
= DCB_PG_ATTR_TC_0
; i
<= DCB_PG_ATTR_TC_7
; i
++) {
554 if (!getall
&& !pg_tb
[i
])
557 if (pg_tb
[DCB_PG_ATTR_TC_ALL
])
558 data
= pg_tb
[DCB_PG_ATTR_TC_ALL
];
561 ret
= nla_parse_nested(param_tb
, DCB_TC_ATTR_PARAM_MAX
,
562 data
, dcbnl_tc_param_nest
);
566 param_nest
= nla_nest_start(dcbnl_skb
, i
);
570 pgid
= DCB_ATTR_VALUE_UNDEFINED
;
571 prio
= DCB_ATTR_VALUE_UNDEFINED
;
572 tc_pct
= DCB_ATTR_VALUE_UNDEFINED
;
573 up_map
= DCB_ATTR_VALUE_UNDEFINED
;
577 netdev
->dcbnl_ops
->getpgtccfgrx(netdev
,
578 i
- DCB_PG_ATTR_TC_0
, &prio
,
579 &pgid
, &tc_pct
, &up_map
);
582 netdev
->dcbnl_ops
->getpgtccfgtx(netdev
,
583 i
- DCB_PG_ATTR_TC_0
, &prio
,
584 &pgid
, &tc_pct
, &up_map
);
587 if (param_tb
[DCB_TC_ATTR_PARAM_PGID
] ||
588 param_tb
[DCB_TC_ATTR_PARAM_ALL
]) {
589 ret
= nla_put_u8(dcbnl_skb
,
590 DCB_TC_ATTR_PARAM_PGID
, pgid
);
594 if (param_tb
[DCB_TC_ATTR_PARAM_UP_MAPPING
] ||
595 param_tb
[DCB_TC_ATTR_PARAM_ALL
]) {
596 ret
= nla_put_u8(dcbnl_skb
,
597 DCB_TC_ATTR_PARAM_UP_MAPPING
, up_map
);
601 if (param_tb
[DCB_TC_ATTR_PARAM_STRICT_PRIO
] ||
602 param_tb
[DCB_TC_ATTR_PARAM_ALL
]) {
603 ret
= nla_put_u8(dcbnl_skb
,
604 DCB_TC_ATTR_PARAM_STRICT_PRIO
, prio
);
608 if (param_tb
[DCB_TC_ATTR_PARAM_BW_PCT
] ||
609 param_tb
[DCB_TC_ATTR_PARAM_ALL
]) {
610 ret
= nla_put_u8(dcbnl_skb
, DCB_TC_ATTR_PARAM_BW_PCT
,
615 nla_nest_end(dcbnl_skb
, param_nest
);
618 if (pg_tb
[DCB_PG_ATTR_BW_ID_ALL
])
623 for (i
= DCB_PG_ATTR_BW_ID_0
; i
<= DCB_PG_ATTR_BW_ID_7
; i
++) {
624 if (!getall
&& !pg_tb
[i
])
627 tc_pct
= DCB_ATTR_VALUE_UNDEFINED
;
631 netdev
->dcbnl_ops
->getpgbwgcfgrx(netdev
,
632 i
- DCB_PG_ATTR_BW_ID_0
, &tc_pct
);
635 netdev
->dcbnl_ops
->getpgbwgcfgtx(netdev
,
636 i
- DCB_PG_ATTR_BW_ID_0
, &tc_pct
);
638 ret
= nla_put_u8(dcbnl_skb
, i
, tc_pct
);
644 nla_nest_end(dcbnl_skb
, pg_nest
);
646 nlmsg_end(dcbnl_skb
, nlh
);
648 ret
= rtnl_unicast(dcbnl_skb
, &init_net
, pid
);
655 nla_nest_cancel(dcbnl_skb
, param_nest
);
657 nla_nest_cancel(dcbnl_skb
, pg_nest
);
666 static int dcbnl_pgtx_getcfg(struct net_device
*netdev
, struct nlattr
**tb
,
667 u32 pid
, u32 seq
, u16 flags
)
669 return __dcbnl_pg_getcfg(netdev
, tb
, pid
, seq
, flags
, 0);
672 static int dcbnl_pgrx_getcfg(struct net_device
*netdev
, struct nlattr
**tb
,
673 u32 pid
, u32 seq
, u16 flags
)
675 return __dcbnl_pg_getcfg(netdev
, tb
, pid
, seq
, flags
, 1);
678 static int dcbnl_setstate(struct net_device
*netdev
, struct nlattr
**tb
,
679 u32 pid
, u32 seq
, u16 flags
)
684 if (!tb
[DCB_ATTR_STATE
] || !netdev
->dcbnl_ops
->setstate
)
687 value
= nla_get_u8(tb
[DCB_ATTR_STATE
]);
689 netdev
->dcbnl_ops
->setstate(netdev
, value
);
691 ret
= dcbnl_reply(0, RTM_SETDCB
, DCB_CMD_SSTATE
, DCB_ATTR_STATE
,
697 static int dcbnl_setpfccfg(struct net_device
*netdev
, struct nlattr
**tb
,
698 u32 pid
, u32 seq
, u16 flags
)
700 struct nlattr
*data
[DCB_PFC_UP_ATTR_MAX
+ 1];
705 if (!tb
[DCB_ATTR_PFC_CFG
] || !netdev
->dcbnl_ops
->setpfccfg
)
708 ret
= nla_parse_nested(data
, DCB_PFC_UP_ATTR_MAX
,
709 tb
[DCB_ATTR_PFC_CFG
],
714 for (i
= DCB_PFC_UP_ATTR_0
; i
<= DCB_PFC_UP_ATTR_7
; i
++) {
717 value
= nla_get_u8(data
[i
]);
718 netdev
->dcbnl_ops
->setpfccfg(netdev
,
719 data
[i
]->nla_type
- DCB_PFC_UP_ATTR_0
, value
);
722 ret
= dcbnl_reply(0, RTM_SETDCB
, DCB_CMD_PFC_SCFG
, DCB_ATTR_PFC_CFG
,
728 static int dcbnl_setall(struct net_device
*netdev
, struct nlattr
**tb
,
729 u32 pid
, u32 seq
, u16 flags
)
733 if (!tb
[DCB_ATTR_SET_ALL
] || !netdev
->dcbnl_ops
->setall
)
736 ret
= dcbnl_reply(netdev
->dcbnl_ops
->setall(netdev
), RTM_SETDCB
,
737 DCB_CMD_SET_ALL
, DCB_ATTR_SET_ALL
, pid
, seq
, flags
);
742 static int __dcbnl_pg_setcfg(struct net_device
*netdev
, struct nlattr
**tb
,
743 u32 pid
, u32 seq
, u16 flags
, int dir
)
745 struct nlattr
*pg_tb
[DCB_PG_ATTR_MAX
+ 1];
746 struct nlattr
*param_tb
[DCB_TC_ATTR_PARAM_MAX
+ 1];
754 if (!tb
[DCB_ATTR_PG_CFG
] ||
755 !netdev
->dcbnl_ops
->setpgtccfgtx
||
756 !netdev
->dcbnl_ops
->setpgtccfgrx
||
757 !netdev
->dcbnl_ops
->setpgbwgcfgtx
||
758 !netdev
->dcbnl_ops
->setpgbwgcfgrx
)
761 ret
= nla_parse_nested(pg_tb
, DCB_PG_ATTR_MAX
,
762 tb
[DCB_ATTR_PG_CFG
], dcbnl_pg_nest
);
766 for (i
= DCB_PG_ATTR_TC_0
; i
<= DCB_PG_ATTR_TC_7
; i
++) {
770 ret
= nla_parse_nested(param_tb
, DCB_TC_ATTR_PARAM_MAX
,
771 pg_tb
[i
], dcbnl_tc_param_nest
);
775 pgid
= DCB_ATTR_VALUE_UNDEFINED
;
776 prio
= DCB_ATTR_VALUE_UNDEFINED
;
777 tc_pct
= DCB_ATTR_VALUE_UNDEFINED
;
778 up_map
= DCB_ATTR_VALUE_UNDEFINED
;
780 if (param_tb
[DCB_TC_ATTR_PARAM_STRICT_PRIO
])
782 nla_get_u8(param_tb
[DCB_TC_ATTR_PARAM_STRICT_PRIO
]);
784 if (param_tb
[DCB_TC_ATTR_PARAM_PGID
])
785 pgid
= nla_get_u8(param_tb
[DCB_TC_ATTR_PARAM_PGID
]);
787 if (param_tb
[DCB_TC_ATTR_PARAM_BW_PCT
])
788 tc_pct
= nla_get_u8(param_tb
[DCB_TC_ATTR_PARAM_BW_PCT
]);
790 if (param_tb
[DCB_TC_ATTR_PARAM_UP_MAPPING
])
792 nla_get_u8(param_tb
[DCB_TC_ATTR_PARAM_UP_MAPPING
]);
794 /* dir: Tx = 0, Rx = 1 */
797 netdev
->dcbnl_ops
->setpgtccfgrx(netdev
,
798 i
- DCB_PG_ATTR_TC_0
,
799 prio
, pgid
, tc_pct
, up_map
);
802 netdev
->dcbnl_ops
->setpgtccfgtx(netdev
,
803 i
- DCB_PG_ATTR_TC_0
,
804 prio
, pgid
, tc_pct
, up_map
);
808 for (i
= DCB_PG_ATTR_BW_ID_0
; i
<= DCB_PG_ATTR_BW_ID_7
; i
++) {
812 tc_pct
= nla_get_u8(pg_tb
[i
]);
814 /* dir: Tx = 0, Rx = 1 */
817 netdev
->dcbnl_ops
->setpgbwgcfgrx(netdev
,
818 i
- DCB_PG_ATTR_BW_ID_0
, tc_pct
);
821 netdev
->dcbnl_ops
->setpgbwgcfgtx(netdev
,
822 i
- DCB_PG_ATTR_BW_ID_0
, tc_pct
);
826 ret
= dcbnl_reply(0, RTM_SETDCB
,
827 (dir
? DCB_CMD_PGRX_SCFG
: DCB_CMD_PGTX_SCFG
),
828 DCB_ATTR_PG_CFG
, pid
, seq
, flags
);
834 static int dcbnl_pgtx_setcfg(struct net_device
*netdev
, struct nlattr
**tb
,
835 u32 pid
, u32 seq
, u16 flags
)
837 return __dcbnl_pg_setcfg(netdev
, tb
, pid
, seq
, flags
, 0);
840 static int dcbnl_pgrx_setcfg(struct net_device
*netdev
, struct nlattr
**tb
,
841 u32 pid
, u32 seq
, u16 flags
)
843 return __dcbnl_pg_setcfg(netdev
, tb
, pid
, seq
, flags
, 1);
846 static int dcb_doit(struct sk_buff
*skb
, struct nlmsghdr
*nlh
, void *arg
)
848 struct net
*net
= sock_net(skb
->sk
);
849 struct net_device
*netdev
;
850 struct dcbmsg
*dcb
= (struct dcbmsg
*)NLMSG_DATA(nlh
);
851 struct nlattr
*tb
[DCB_ATTR_MAX
+ 1];
852 u32 pid
= skb
? NETLINK_CB(skb
).pid
: 0;
855 if (net
!= &init_net
)
858 ret
= nlmsg_parse(nlh
, sizeof(*dcb
), tb
, DCB_ATTR_MAX
,
863 if (!tb
[DCB_ATTR_IFNAME
])
866 netdev
= dev_get_by_name(&init_net
, nla_data(tb
[DCB_ATTR_IFNAME
]));
870 if (!netdev
->dcbnl_ops
)
875 ret
= dcbnl_getstate(netdev
, tb
, pid
, nlh
->nlmsg_seq
,
878 case DCB_CMD_PFC_GCFG
:
879 ret
= dcbnl_getpfccfg(netdev
, tb
, pid
, nlh
->nlmsg_seq
,
882 case DCB_CMD_GPERM_HWADDR
:
883 ret
= dcbnl_getperm_hwaddr(netdev
, tb
, pid
, nlh
->nlmsg_seq
,
886 case DCB_CMD_PGTX_GCFG
:
887 ret
= dcbnl_pgtx_getcfg(netdev
, tb
, pid
, nlh
->nlmsg_seq
,
890 case DCB_CMD_PGRX_GCFG
:
891 ret
= dcbnl_pgrx_getcfg(netdev
, tb
, pid
, nlh
->nlmsg_seq
,
895 ret
= dcbnl_setstate(netdev
, tb
, pid
, nlh
->nlmsg_seq
,
898 case DCB_CMD_PFC_SCFG
:
899 ret
= dcbnl_setpfccfg(netdev
, tb
, pid
, nlh
->nlmsg_seq
,
903 case DCB_CMD_SET_ALL
:
904 ret
= dcbnl_setall(netdev
, tb
, pid
, nlh
->nlmsg_seq
,
907 case DCB_CMD_PGTX_SCFG
:
908 ret
= dcbnl_pgtx_setcfg(netdev
, tb
, pid
, nlh
->nlmsg_seq
,
911 case DCB_CMD_PGRX_SCFG
:
912 ret
= dcbnl_pgrx_setcfg(netdev
, tb
, pid
, nlh
->nlmsg_seq
,
916 ret
= dcbnl_getcap(netdev
, tb
, pid
, nlh
->nlmsg_seq
,
919 case DCB_CMD_GNUMTCS
:
920 ret
= dcbnl_getnumtcs(netdev
, tb
, pid
, nlh
->nlmsg_seq
,
923 case DCB_CMD_SNUMTCS
:
924 ret
= dcbnl_setnumtcs(netdev
, tb
, pid
, nlh
->nlmsg_seq
,
927 case DCB_CMD_PFC_GSTATE
:
928 ret
= dcbnl_getpfcstate(netdev
, tb
, pid
, nlh
->nlmsg_seq
,
931 case DCB_CMD_PFC_SSTATE
:
932 ret
= dcbnl_setpfcstate(netdev
, tb
, pid
, nlh
->nlmsg_seq
,
945 static int __init
dcbnl_init(void)
947 rtnl_register(PF_UNSPEC
, RTM_GETDCB
, dcb_doit
, NULL
);
948 rtnl_register(PF_UNSPEC
, RTM_SETDCB
, dcb_doit
, NULL
);
952 module_init(dcbnl_init
);
954 static void __exit
dcbnl_exit(void)
956 rtnl_unregister(PF_UNSPEC
, RTM_GETDCB
);
957 rtnl_unregister(PF_UNSPEC
, RTM_SETDCB
);
959 module_exit(dcbnl_exit
);