diff options
Diffstat (limited to 'net/dcb')
-rw-r--r-- | net/dcb/dcbnl.c | 133 |
1 files changed, 133 insertions, 0 deletions
diff --git a/net/dcb/dcbnl.c b/net/dcb/dcbnl.c index 8f83ad859d9b..075af0a08d84 100644 --- a/net/dcb/dcbnl.c +++ b/net/dcb/dcbnl.c | |||
@@ -69,6 +69,7 @@ static const struct nla_policy dcbnl_rtnl_policy[DCB_ATTR_MAX + 1] = { | |||
69 | [DCB_ATTR_APP] = {.type = NLA_NESTED}, | 69 | [DCB_ATTR_APP] = {.type = NLA_NESTED}, |
70 | [DCB_ATTR_IEEE] = {.type = NLA_NESTED}, | 70 | [DCB_ATTR_IEEE] = {.type = NLA_NESTED}, |
71 | [DCB_ATTR_DCBX] = {.type = NLA_U8}, | 71 | [DCB_ATTR_DCBX] = {.type = NLA_U8}, |
72 | [DCB_ATTR_FEATCFG] = {.type = NLA_NESTED}, | ||
72 | }; | 73 | }; |
73 | 74 | ||
74 | /* DCB priority flow control to User Priority nested attributes */ | 75 | /* DCB priority flow control to User Priority nested attributes */ |
@@ -182,6 +183,14 @@ static const struct nla_policy dcbnl_ieee_app[DCB_ATTR_IEEE_APP_MAX + 1] = { | |||
182 | [DCB_ATTR_IEEE_APP] = {.len = sizeof(struct dcb_app)}, | 183 | [DCB_ATTR_IEEE_APP] = {.len = sizeof(struct dcb_app)}, |
183 | }; | 184 | }; |
184 | 185 | ||
186 | /* DCB number of traffic classes nested attributes. */ | ||
187 | static const struct nla_policy dcbnl_featcfg_nest[DCB_FEATCFG_ATTR_MAX + 1] = { | ||
188 | [DCB_FEATCFG_ATTR_ALL] = {.type = NLA_FLAG}, | ||
189 | [DCB_FEATCFG_ATTR_PG] = {.type = NLA_U8}, | ||
190 | [DCB_FEATCFG_ATTR_PFC] = {.type = NLA_U8}, | ||
191 | [DCB_FEATCFG_ATTR_APP] = {.type = NLA_U8}, | ||
192 | }; | ||
193 | |||
185 | static LIST_HEAD(dcb_app_list); | 194 | static LIST_HEAD(dcb_app_list); |
186 | static DEFINE_SPINLOCK(dcb_lock); | 195 | static DEFINE_SPINLOCK(dcb_lock); |
187 | 196 | ||
@@ -1306,6 +1315,122 @@ static int dcbnl_setdcbx(struct net_device *netdev, struct nlattr **tb, | |||
1306 | return ret; | 1315 | return ret; |
1307 | } | 1316 | } |
1308 | 1317 | ||
1318 | static int dcbnl_getfeatcfg(struct net_device *netdev, struct nlattr **tb, | ||
1319 | u32 pid, u32 seq, u16 flags) | ||
1320 | { | ||
1321 | struct sk_buff *dcbnl_skb; | ||
1322 | struct nlmsghdr *nlh; | ||
1323 | struct dcbmsg *dcb; | ||
1324 | struct nlattr *data[DCB_FEATCFG_ATTR_MAX + 1], *nest; | ||
1325 | u8 value; | ||
1326 | int ret = -EINVAL; | ||
1327 | int i; | ||
1328 | int getall = 0; | ||
1329 | |||
1330 | if (!tb[DCB_ATTR_FEATCFG] || !netdev->dcbnl_ops->getfeatcfg) | ||
1331 | return ret; | ||
1332 | |||
1333 | ret = nla_parse_nested(data, DCB_FEATCFG_ATTR_MAX, tb[DCB_ATTR_FEATCFG], | ||
1334 | dcbnl_featcfg_nest); | ||
1335 | if (ret) { | ||
1336 | ret = -EINVAL; | ||
1337 | goto err_out; | ||
1338 | } | ||
1339 | |||
1340 | dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
1341 | if (!dcbnl_skb) { | ||
1342 | ret = -EINVAL; | ||
1343 | goto err_out; | ||
1344 | } | ||
1345 | |||
1346 | nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); | ||
1347 | |||
1348 | dcb = NLMSG_DATA(nlh); | ||
1349 | dcb->dcb_family = AF_UNSPEC; | ||
1350 | dcb->cmd = DCB_CMD_GFEATCFG; | ||
1351 | |||
1352 | nest = nla_nest_start(dcbnl_skb, DCB_ATTR_FEATCFG); | ||
1353 | if (!nest) { | ||
1354 | ret = -EINVAL; | ||
1355 | goto err; | ||
1356 | } | ||
1357 | |||
1358 | if (data[DCB_FEATCFG_ATTR_ALL]) | ||
1359 | getall = 1; | ||
1360 | |||
1361 | for (i = DCB_FEATCFG_ATTR_ALL+1; i <= DCB_FEATCFG_ATTR_MAX; i++) { | ||
1362 | if (!getall && !data[i]) | ||
1363 | continue; | ||
1364 | |||
1365 | ret = netdev->dcbnl_ops->getfeatcfg(netdev, i, &value); | ||
1366 | if (!ret) { | ||
1367 | ret = nla_put_u8(dcbnl_skb, i, value); | ||
1368 | |||
1369 | if (ret) { | ||
1370 | nla_nest_cancel(dcbnl_skb, nest); | ||
1371 | ret = -EINVAL; | ||
1372 | goto err; | ||
1373 | } | ||
1374 | } else | ||
1375 | goto err; | ||
1376 | } | ||
1377 | nla_nest_end(dcbnl_skb, nest); | ||
1378 | |||
1379 | nlmsg_end(dcbnl_skb, nlh); | ||
1380 | |||
1381 | ret = rtnl_unicast(dcbnl_skb, &init_net, pid); | ||
1382 | if (ret) { | ||
1383 | ret = -EINVAL; | ||
1384 | goto err_out; | ||
1385 | } | ||
1386 | |||
1387 | return 0; | ||
1388 | nlmsg_failure: | ||
1389 | err: | ||
1390 | kfree_skb(dcbnl_skb); | ||
1391 | err_out: | ||
1392 | return ret; | ||
1393 | } | ||
1394 | |||
1395 | static int dcbnl_setfeatcfg(struct net_device *netdev, struct nlattr **tb, | ||
1396 | u32 pid, u32 seq, u16 flags) | ||
1397 | { | ||
1398 | struct nlattr *data[DCB_FEATCFG_ATTR_MAX + 1]; | ||
1399 | int ret = -EINVAL; | ||
1400 | u8 value; | ||
1401 | int i; | ||
1402 | |||
1403 | if (!tb[DCB_ATTR_FEATCFG] || !netdev->dcbnl_ops->setfeatcfg) | ||
1404 | return ret; | ||
1405 | |||
1406 | ret = nla_parse_nested(data, DCB_FEATCFG_ATTR_MAX, tb[DCB_ATTR_FEATCFG], | ||
1407 | dcbnl_featcfg_nest); | ||
1408 | |||
1409 | if (ret) { | ||
1410 | ret = -EINVAL; | ||
1411 | goto err; | ||
1412 | } | ||
1413 | |||
1414 | for (i = DCB_FEATCFG_ATTR_ALL+1; i <= DCB_FEATCFG_ATTR_MAX; i++) { | ||
1415 | if (data[i] == NULL) | ||
1416 | continue; | ||
1417 | |||
1418 | value = nla_get_u8(data[i]); | ||
1419 | |||
1420 | ret = netdev->dcbnl_ops->setfeatcfg(netdev, i, value); | ||
1421 | |||
1422 | if (ret) | ||
1423 | goto operr; | ||
1424 | } | ||
1425 | |||
1426 | operr: | ||
1427 | ret = dcbnl_reply(!!ret, RTM_SETDCB, DCB_CMD_SFEATCFG, | ||
1428 | DCB_ATTR_FEATCFG, pid, seq, flags); | ||
1429 | |||
1430 | err: | ||
1431 | return ret; | ||
1432 | } | ||
1433 | |||
1309 | static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | 1434 | static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) |
1310 | { | 1435 | { |
1311 | struct net *net = sock_net(skb->sk); | 1436 | struct net *net = sock_net(skb->sk); |
@@ -1427,6 +1552,14 @@ static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
1427 | ret = dcbnl_setdcbx(netdev, tb, pid, nlh->nlmsg_seq, | 1552 | ret = dcbnl_setdcbx(netdev, tb, pid, nlh->nlmsg_seq, |
1428 | nlh->nlmsg_flags); | 1553 | nlh->nlmsg_flags); |
1429 | goto out; | 1554 | goto out; |
1555 | case DCB_CMD_GFEATCFG: | ||
1556 | ret = dcbnl_getfeatcfg(netdev, tb, pid, nlh->nlmsg_seq, | ||
1557 | nlh->nlmsg_flags); | ||
1558 | goto out; | ||
1559 | case DCB_CMD_SFEATCFG: | ||
1560 | ret = dcbnl_setfeatcfg(netdev, tb, pid, nlh->nlmsg_seq, | ||
1561 | nlh->nlmsg_flags); | ||
1562 | goto out; | ||
1430 | default: | 1563 | default: |
1431 | goto errout; | 1564 | goto errout; |
1432 | } | 1565 | } |