diff options
author | Alexander Duyck <alexander.h.duyck@intel.com> | 2008-11-21 00:05:08 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-11-21 00:05:08 -0500 |
commit | 46132188bf72e22ef097f16ed5c969ee8cea1e8b (patch) | |
tree | e776ed8011b8314ff08abf4f3467c07d037fec4f /net/dcb/dcbnl.c | |
parent | 2f90b8657ec942d1880f720e0177ee71df7c8e3c (diff) |
DCB: Add interface to query for the DCB capabilities of an device.
Adds to the netlink interface for Data Center Bridging (DCB), allowing
the DCB capabilities supported by a device to be queried.
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/dcb/dcbnl.c')
-rw-r--r-- | net/dcb/dcbnl.c | 82 |
1 files changed, 82 insertions, 0 deletions
diff --git a/net/dcb/dcbnl.c b/net/dcb/dcbnl.c index 516e8be83d72..de61d64d102d 100644 --- a/net/dcb/dcbnl.c +++ b/net/dcb/dcbnl.c | |||
@@ -61,6 +61,7 @@ static struct nla_policy dcbnl_rtnl_policy[DCB_ATTR_MAX + 1] = { | |||
61 | [DCB_ATTR_PG_CFG] = {.type = NLA_NESTED}, | 61 | [DCB_ATTR_PG_CFG] = {.type = NLA_NESTED}, |
62 | [DCB_ATTR_SET_ALL] = {.type = NLA_U8}, | 62 | [DCB_ATTR_SET_ALL] = {.type = NLA_U8}, |
63 | [DCB_ATTR_PERM_HWADDR] = {.type = NLA_FLAG}, | 63 | [DCB_ATTR_PERM_HWADDR] = {.type = NLA_FLAG}, |
64 | [DCB_ATTR_CAP] = {.type = NLA_NESTED}, | ||
64 | }; | 65 | }; |
65 | 66 | ||
66 | /* DCB priority flow control to User Priority nested attributes */ | 67 | /* DCB priority flow control to User Priority nested attributes */ |
@@ -107,6 +108,17 @@ static struct nla_policy dcbnl_tc_param_nest[DCB_TC_ATTR_PARAM_MAX + 1] = { | |||
107 | [DCB_TC_ATTR_PARAM_ALL] = {.type = NLA_FLAG}, | 108 | [DCB_TC_ATTR_PARAM_ALL] = {.type = NLA_FLAG}, |
108 | }; | 109 | }; |
109 | 110 | ||
111 | /* DCB capabilities nested attributes. */ | ||
112 | static struct nla_policy dcbnl_cap_nest[DCB_CAP_ATTR_MAX + 1] = { | ||
113 | [DCB_CAP_ATTR_ALL] = {.type = NLA_FLAG}, | ||
114 | [DCB_CAP_ATTR_PG] = {.type = NLA_U8}, | ||
115 | [DCB_CAP_ATTR_PFC] = {.type = NLA_U8}, | ||
116 | [DCB_CAP_ATTR_UP2TC] = {.type = NLA_U8}, | ||
117 | [DCB_CAP_ATTR_PG_TCS] = {.type = NLA_U8}, | ||
118 | [DCB_CAP_ATTR_PFC_TCS] = {.type = NLA_U8}, | ||
119 | [DCB_CAP_ATTR_GSP] = {.type = NLA_U8}, | ||
120 | [DCB_CAP_ATTR_BCN] = {.type = NLA_U8}, | ||
121 | }; | ||
110 | 122 | ||
111 | /* standard netlink reply call */ | 123 | /* standard netlink reply call */ |
112 | static int dcbnl_reply(u8 value, u8 event, u8 cmd, u8 attr, u32 pid, | 124 | static int dcbnl_reply(u8 value, u8 event, u8 cmd, u8 attr, u32 pid, |
@@ -269,6 +281,72 @@ err_out: | |||
269 | return -EINVAL; | 281 | return -EINVAL; |
270 | } | 282 | } |
271 | 283 | ||
284 | static int dcbnl_getcap(struct net_device *netdev, struct nlattr **tb, | ||
285 | u32 pid, u32 seq, u16 flags) | ||
286 | { | ||
287 | struct sk_buff *dcbnl_skb; | ||
288 | struct nlmsghdr *nlh; | ||
289 | struct dcbmsg *dcb; | ||
290 | struct nlattr *data[DCB_CAP_ATTR_MAX + 1], *nest; | ||
291 | u8 value; | ||
292 | int ret = -EINVAL; | ||
293 | int i; | ||
294 | int getall = 0; | ||
295 | |||
296 | if (!tb[DCB_ATTR_CAP] || !netdev->dcbnl_ops->getcap) | ||
297 | return ret; | ||
298 | |||
299 | ret = nla_parse_nested(data, DCB_CAP_ATTR_MAX, tb[DCB_ATTR_CAP], | ||
300 | dcbnl_cap_nest); | ||
301 | if (ret) | ||
302 | goto err_out; | ||
303 | |||
304 | dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
305 | if (!dcbnl_skb) | ||
306 | goto err_out; | ||
307 | |||
308 | nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); | ||
309 | |||
310 | dcb = NLMSG_DATA(nlh); | ||
311 | dcb->dcb_family = AF_UNSPEC; | ||
312 | dcb->cmd = DCB_CMD_GCAP; | ||
313 | |||
314 | nest = nla_nest_start(dcbnl_skb, DCB_ATTR_CAP); | ||
315 | if (!nest) | ||
316 | goto err; | ||
317 | |||
318 | if (data[DCB_CAP_ATTR_ALL]) | ||
319 | getall = 1; | ||
320 | |||
321 | for (i = DCB_CAP_ATTR_ALL+1; i <= DCB_CAP_ATTR_MAX; i++) { | ||
322 | if (!getall && !data[i]) | ||
323 | continue; | ||
324 | |||
325 | if (!netdev->dcbnl_ops->getcap(netdev, i, &value)) { | ||
326 | ret = nla_put_u8(dcbnl_skb, i, value); | ||
327 | |||
328 | if (ret) { | ||
329 | nla_nest_cancel(dcbnl_skb, nest); | ||
330 | goto err; | ||
331 | } | ||
332 | } | ||
333 | } | ||
334 | nla_nest_end(dcbnl_skb, nest); | ||
335 | |||
336 | nlmsg_end(dcbnl_skb, nlh); | ||
337 | |||
338 | ret = rtnl_unicast(dcbnl_skb, &init_net, pid); | ||
339 | if (ret) | ||
340 | goto err; | ||
341 | |||
342 | return 0; | ||
343 | nlmsg_failure: | ||
344 | err: | ||
345 | kfree(dcbnl_skb); | ||
346 | err_out: | ||
347 | return -EINVAL; | ||
348 | } | ||
349 | |||
272 | static int __dcbnl_pg_getcfg(struct net_device *netdev, struct nlattr **tb, | 350 | static int __dcbnl_pg_getcfg(struct net_device *netdev, struct nlattr **tb, |
273 | u32 pid, u32 seq, u16 flags, int dir) | 351 | u32 pid, u32 seq, u16 flags, int dir) |
274 | { | 352 | { |
@@ -675,6 +753,10 @@ static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
675 | ret = dcbnl_pgrx_setcfg(netdev, tb, pid, nlh->nlmsg_seq, | 753 | ret = dcbnl_pgrx_setcfg(netdev, tb, pid, nlh->nlmsg_seq, |
676 | nlh->nlmsg_flags); | 754 | nlh->nlmsg_flags); |
677 | goto out; | 755 | goto out; |
756 | case DCB_CMD_GCAP: | ||
757 | ret = dcbnl_getcap(netdev, tb, pid, nlh->nlmsg_seq, | ||
758 | nlh->nlmsg_flags); | ||
759 | goto out; | ||
678 | default: | 760 | default: |
679 | goto errout; | 761 | goto errout; |
680 | } | 762 | } |