aboutsummaryrefslogtreecommitdiffstats
path: root/net/dcb/dcbnl.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/dcb/dcbnl.c')
-rw-r--r--net/dcb/dcbnl.c133
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. */
187static 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
185static LIST_HEAD(dcb_app_list); 194static LIST_HEAD(dcb_app_list);
186static DEFINE_SPINLOCK(dcb_lock); 195static 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
1318static 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;
1388nlmsg_failure:
1389err:
1390 kfree_skb(dcbnl_skb);
1391err_out:
1392 return ret;
1393}
1394
1395static 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
1426operr:
1427 ret = dcbnl_reply(!!ret, RTM_SETDCB, DCB_CMD_SFEATCFG,
1428 DCB_ATTR_FEATCFG, pid, seq, flags);
1429
1430err:
1431 return ret;
1432}
1433
1309static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) 1434static 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 }