diff options
Diffstat (limited to 'net/dcb/dcbnl.c')
-rw-r--r-- | net/dcb/dcbnl.c | 677 |
1 files changed, 547 insertions, 130 deletions
diff --git a/net/dcb/dcbnl.c b/net/dcb/dcbnl.c index 3609eacaf4ce..3cb56af4e13c 100644 --- a/net/dcb/dcbnl.c +++ b/net/dcb/dcbnl.c | |||
@@ -1166,64 +1166,6 @@ err: | |||
1166 | return ret; | 1166 | return ret; |
1167 | } | 1167 | } |
1168 | 1168 | ||
1169 | /* Handle IEEE 802.1Qaz SET commands. If any requested operation can not | ||
1170 | * be completed the entire msg is aborted and error value is returned. | ||
1171 | * No attempt is made to reconcile the case where only part of the | ||
1172 | * cmd can be completed. | ||
1173 | */ | ||
1174 | static int dcbnl_ieee_set(struct net_device *netdev, struct nlattr **tb, | ||
1175 | u32 pid, u32 seq, u16 flags) | ||
1176 | { | ||
1177 | const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; | ||
1178 | struct nlattr *ieee[DCB_ATTR_IEEE_MAX + 1]; | ||
1179 | int err = -EOPNOTSUPP; | ||
1180 | |||
1181 | if (!ops) | ||
1182 | goto err; | ||
1183 | |||
1184 | err = nla_parse_nested(ieee, DCB_ATTR_IEEE_MAX, | ||
1185 | tb[DCB_ATTR_IEEE], dcbnl_ieee_policy); | ||
1186 | if (err) | ||
1187 | goto err; | ||
1188 | |||
1189 | if (ieee[DCB_ATTR_IEEE_ETS] && ops->ieee_setets) { | ||
1190 | struct ieee_ets *ets = nla_data(ieee[DCB_ATTR_IEEE_ETS]); | ||
1191 | err = ops->ieee_setets(netdev, ets); | ||
1192 | if (err) | ||
1193 | goto err; | ||
1194 | } | ||
1195 | |||
1196 | if (ieee[DCB_ATTR_IEEE_PFC] && ops->ieee_setpfc) { | ||
1197 | struct ieee_pfc *pfc = nla_data(ieee[DCB_ATTR_IEEE_PFC]); | ||
1198 | err = ops->ieee_setpfc(netdev, pfc); | ||
1199 | if (err) | ||
1200 | goto err; | ||
1201 | } | ||
1202 | |||
1203 | if (ieee[DCB_ATTR_IEEE_APP_TABLE]) { | ||
1204 | struct nlattr *attr; | ||
1205 | int rem; | ||
1206 | |||
1207 | nla_for_each_nested(attr, ieee[DCB_ATTR_IEEE_APP_TABLE], rem) { | ||
1208 | struct dcb_app *app_data; | ||
1209 | if (nla_type(attr) != DCB_ATTR_IEEE_APP) | ||
1210 | continue; | ||
1211 | app_data = nla_data(attr); | ||
1212 | if (ops->ieee_setapp) | ||
1213 | err = ops->ieee_setapp(netdev, app_data); | ||
1214 | else | ||
1215 | err = dcb_setapp(netdev, app_data); | ||
1216 | if (err) | ||
1217 | goto err; | ||
1218 | } | ||
1219 | } | ||
1220 | |||
1221 | err: | ||
1222 | dcbnl_reply(err, RTM_SETDCB, DCB_CMD_IEEE_SET, DCB_ATTR_IEEE, | ||
1223 | pid, seq, flags); | ||
1224 | return err; | ||
1225 | } | ||
1226 | |||
1227 | static int dcbnl_build_peer_app(struct net_device *netdev, struct sk_buff* skb, | 1169 | static int dcbnl_build_peer_app(struct net_device *netdev, struct sk_buff* skb, |
1228 | int app_nested_type, int app_info_type, | 1170 | int app_nested_type, int app_info_type, |
1229 | int app_entry_type) | 1171 | int app_entry_type) |
@@ -1279,29 +1221,13 @@ nla_put_failure: | |||
1279 | } | 1221 | } |
1280 | 1222 | ||
1281 | /* Handle IEEE 802.1Qaz GET commands. */ | 1223 | /* Handle IEEE 802.1Qaz GET commands. */ |
1282 | static int dcbnl_ieee_get(struct net_device *netdev, struct nlattr **tb, | 1224 | static int dcbnl_ieee_fill(struct sk_buff *skb, struct net_device *netdev) |
1283 | u32 pid, u32 seq, u16 flags) | ||
1284 | { | 1225 | { |
1285 | struct sk_buff *skb; | ||
1286 | struct nlmsghdr *nlh; | ||
1287 | struct dcbmsg *dcb; | ||
1288 | struct nlattr *ieee, *app; | 1226 | struct nlattr *ieee, *app; |
1289 | struct dcb_app_type *itr; | 1227 | struct dcb_app_type *itr; |
1290 | const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; | 1228 | const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; |
1291 | int err; | 1229 | int dcbx; |
1292 | 1230 | int err = -EMSGSIZE; | |
1293 | if (!ops) | ||
1294 | return -EOPNOTSUPP; | ||
1295 | |||
1296 | skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
1297 | if (!skb) | ||
1298 | return -ENOBUFS; | ||
1299 | |||
1300 | nlh = NLMSG_NEW(skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); | ||
1301 | |||
1302 | dcb = NLMSG_DATA(nlh); | ||
1303 | dcb->dcb_family = AF_UNSPEC; | ||
1304 | dcb->cmd = DCB_CMD_IEEE_GET; | ||
1305 | 1231 | ||
1306 | NLA_PUT_STRING(skb, DCB_ATTR_IFNAME, netdev->name); | 1232 | NLA_PUT_STRING(skb, DCB_ATTR_IFNAME, netdev->name); |
1307 | 1233 | ||
@@ -1338,6 +1264,12 @@ static int dcbnl_ieee_get(struct net_device *netdev, struct nlattr **tb, | |||
1338 | } | 1264 | } |
1339 | } | 1265 | } |
1340 | } | 1266 | } |
1267 | |||
1268 | if (netdev->dcbnl_ops->getdcbx) | ||
1269 | dcbx = netdev->dcbnl_ops->getdcbx(netdev); | ||
1270 | else | ||
1271 | dcbx = -EOPNOTSUPP; | ||
1272 | |||
1341 | spin_unlock(&dcb_lock); | 1273 | spin_unlock(&dcb_lock); |
1342 | nla_nest_end(skb, app); | 1274 | nla_nest_end(skb, app); |
1343 | 1275 | ||
@@ -1366,16 +1298,413 @@ static int dcbnl_ieee_get(struct net_device *netdev, struct nlattr **tb, | |||
1366 | } | 1298 | } |
1367 | 1299 | ||
1368 | nla_nest_end(skb, ieee); | 1300 | nla_nest_end(skb, ieee); |
1369 | nlmsg_end(skb, nlh); | 1301 | if (dcbx >= 0) { |
1302 | err = nla_put_u8(skb, DCB_ATTR_DCBX, dcbx); | ||
1303 | if (err) | ||
1304 | goto nla_put_failure; | ||
1305 | } | ||
1306 | |||
1307 | return 0; | ||
1370 | 1308 | ||
1371 | return rtnl_unicast(skb, &init_net, pid); | ||
1372 | nla_put_failure: | 1309 | nla_put_failure: |
1373 | nlmsg_cancel(skb, nlh); | 1310 | return err; |
1374 | nlmsg_failure: | ||
1375 | kfree_skb(skb); | ||
1376 | return -1; | ||
1377 | } | 1311 | } |
1378 | 1312 | ||
1313 | static int dcbnl_cee_pg_fill(struct sk_buff *skb, struct net_device *dev, | ||
1314 | int dir) | ||
1315 | { | ||
1316 | u8 pgid, up_map, prio, tc_pct; | ||
1317 | const struct dcbnl_rtnl_ops *ops = dev->dcbnl_ops; | ||
1318 | int i = dir ? DCB_ATTR_CEE_TX_PG : DCB_ATTR_CEE_RX_PG; | ||
1319 | struct nlattr *pg = nla_nest_start(skb, i); | ||
1320 | |||
1321 | if (!pg) | ||
1322 | goto nla_put_failure; | ||
1323 | |||
1324 | for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) { | ||
1325 | struct nlattr *tc_nest = nla_nest_start(skb, i); | ||
1326 | |||
1327 | if (!tc_nest) | ||
1328 | goto nla_put_failure; | ||
1329 | |||
1330 | pgid = DCB_ATTR_VALUE_UNDEFINED; | ||
1331 | prio = DCB_ATTR_VALUE_UNDEFINED; | ||
1332 | tc_pct = DCB_ATTR_VALUE_UNDEFINED; | ||
1333 | up_map = DCB_ATTR_VALUE_UNDEFINED; | ||
1334 | |||
1335 | if (!dir) | ||
1336 | ops->getpgtccfgrx(dev, i - DCB_PG_ATTR_TC_0, | ||
1337 | &prio, &pgid, &tc_pct, &up_map); | ||
1338 | else | ||
1339 | ops->getpgtccfgtx(dev, i - DCB_PG_ATTR_TC_0, | ||
1340 | &prio, &pgid, &tc_pct, &up_map); | ||
1341 | |||
1342 | NLA_PUT_U8(skb, DCB_TC_ATTR_PARAM_PGID, pgid); | ||
1343 | NLA_PUT_U8(skb, DCB_TC_ATTR_PARAM_UP_MAPPING, up_map); | ||
1344 | NLA_PUT_U8(skb, DCB_TC_ATTR_PARAM_STRICT_PRIO, prio); | ||
1345 | NLA_PUT_U8(skb, DCB_TC_ATTR_PARAM_BW_PCT, tc_pct); | ||
1346 | nla_nest_end(skb, tc_nest); | ||
1347 | } | ||
1348 | |||
1349 | for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) { | ||
1350 | tc_pct = DCB_ATTR_VALUE_UNDEFINED; | ||
1351 | |||
1352 | if (!dir) | ||
1353 | ops->getpgbwgcfgrx(dev, i - DCB_PG_ATTR_BW_ID_0, | ||
1354 | &tc_pct); | ||
1355 | else | ||
1356 | ops->getpgbwgcfgtx(dev, i - DCB_PG_ATTR_BW_ID_0, | ||
1357 | &tc_pct); | ||
1358 | NLA_PUT_U8(skb, i, tc_pct); | ||
1359 | } | ||
1360 | nla_nest_end(skb, pg); | ||
1361 | return 0; | ||
1362 | |||
1363 | nla_put_failure: | ||
1364 | return -EMSGSIZE; | ||
1365 | } | ||
1366 | |||
1367 | static int dcbnl_cee_fill(struct sk_buff *skb, struct net_device *netdev) | ||
1368 | { | ||
1369 | struct nlattr *cee, *app; | ||
1370 | struct dcb_app_type *itr; | ||
1371 | const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; | ||
1372 | int dcbx, i, err = -EMSGSIZE; | ||
1373 | u8 value; | ||
1374 | |||
1375 | NLA_PUT_STRING(skb, DCB_ATTR_IFNAME, netdev->name); | ||
1376 | |||
1377 | cee = nla_nest_start(skb, DCB_ATTR_CEE); | ||
1378 | if (!cee) | ||
1379 | goto nla_put_failure; | ||
1380 | |||
1381 | /* local pg */ | ||
1382 | if (ops->getpgtccfgtx && ops->getpgbwgcfgtx) { | ||
1383 | err = dcbnl_cee_pg_fill(skb, netdev, 1); | ||
1384 | if (err) | ||
1385 | goto nla_put_failure; | ||
1386 | } | ||
1387 | |||
1388 | if (ops->getpgtccfgrx && ops->getpgbwgcfgrx) { | ||
1389 | err = dcbnl_cee_pg_fill(skb, netdev, 0); | ||
1390 | if (err) | ||
1391 | goto nla_put_failure; | ||
1392 | } | ||
1393 | |||
1394 | /* local pfc */ | ||
1395 | if (ops->getpfccfg) { | ||
1396 | struct nlattr *pfc_nest = nla_nest_start(skb, DCB_ATTR_CEE_PFC); | ||
1397 | |||
1398 | if (!pfc_nest) | ||
1399 | goto nla_put_failure; | ||
1400 | |||
1401 | for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) { | ||
1402 | ops->getpfccfg(netdev, i - DCB_PFC_UP_ATTR_0, &value); | ||
1403 | NLA_PUT_U8(skb, i, value); | ||
1404 | } | ||
1405 | nla_nest_end(skb, pfc_nest); | ||
1406 | } | ||
1407 | |||
1408 | /* local app */ | ||
1409 | spin_lock(&dcb_lock); | ||
1410 | app = nla_nest_start(skb, DCB_ATTR_CEE_APP_TABLE); | ||
1411 | if (!app) | ||
1412 | goto dcb_unlock; | ||
1413 | |||
1414 | list_for_each_entry(itr, &dcb_app_list, list) { | ||
1415 | if (strncmp(itr->name, netdev->name, IFNAMSIZ) == 0) { | ||
1416 | struct nlattr *app_nest = nla_nest_start(skb, | ||
1417 | DCB_ATTR_APP); | ||
1418 | if (!app_nest) | ||
1419 | goto dcb_unlock; | ||
1420 | |||
1421 | err = nla_put_u8(skb, DCB_APP_ATTR_IDTYPE, | ||
1422 | itr->app.selector); | ||
1423 | if (err) | ||
1424 | goto dcb_unlock; | ||
1425 | |||
1426 | err = nla_put_u16(skb, DCB_APP_ATTR_ID, | ||
1427 | itr->app.protocol); | ||
1428 | if (err) | ||
1429 | goto dcb_unlock; | ||
1430 | |||
1431 | err = nla_put_u8(skb, DCB_APP_ATTR_PRIORITY, | ||
1432 | itr->app.priority); | ||
1433 | if (err) | ||
1434 | goto dcb_unlock; | ||
1435 | |||
1436 | nla_nest_end(skb, app_nest); | ||
1437 | } | ||
1438 | } | ||
1439 | nla_nest_end(skb, app); | ||
1440 | |||
1441 | if (netdev->dcbnl_ops->getdcbx) | ||
1442 | dcbx = netdev->dcbnl_ops->getdcbx(netdev); | ||
1443 | else | ||
1444 | dcbx = -EOPNOTSUPP; | ||
1445 | |||
1446 | spin_unlock(&dcb_lock); | ||
1447 | |||
1448 | /* features flags */ | ||
1449 | if (ops->getfeatcfg) { | ||
1450 | struct nlattr *feat = nla_nest_start(skb, DCB_ATTR_CEE_FEAT); | ||
1451 | if (!feat) | ||
1452 | goto nla_put_failure; | ||
1453 | |||
1454 | for (i = DCB_FEATCFG_ATTR_ALL + 1; i <= DCB_FEATCFG_ATTR_MAX; | ||
1455 | i++) | ||
1456 | if (!ops->getfeatcfg(netdev, i, &value)) | ||
1457 | NLA_PUT_U8(skb, i, value); | ||
1458 | |||
1459 | nla_nest_end(skb, feat); | ||
1460 | } | ||
1461 | |||
1462 | /* peer info if available */ | ||
1463 | if (ops->cee_peer_getpg) { | ||
1464 | struct cee_pg pg; | ||
1465 | err = ops->cee_peer_getpg(netdev, &pg); | ||
1466 | if (!err) | ||
1467 | NLA_PUT(skb, DCB_ATTR_CEE_PEER_PG, sizeof(pg), &pg); | ||
1468 | } | ||
1469 | |||
1470 | if (ops->cee_peer_getpfc) { | ||
1471 | struct cee_pfc pfc; | ||
1472 | err = ops->cee_peer_getpfc(netdev, &pfc); | ||
1473 | if (!err) | ||
1474 | NLA_PUT(skb, DCB_ATTR_CEE_PEER_PFC, sizeof(pfc), &pfc); | ||
1475 | } | ||
1476 | |||
1477 | if (ops->peer_getappinfo && ops->peer_getapptable) { | ||
1478 | err = dcbnl_build_peer_app(netdev, skb, | ||
1479 | DCB_ATTR_CEE_PEER_APP_TABLE, | ||
1480 | DCB_ATTR_CEE_PEER_APP_INFO, | ||
1481 | DCB_ATTR_CEE_PEER_APP); | ||
1482 | if (err) | ||
1483 | goto nla_put_failure; | ||
1484 | } | ||
1485 | nla_nest_end(skb, cee); | ||
1486 | |||
1487 | /* DCBX state */ | ||
1488 | if (dcbx >= 0) { | ||
1489 | err = nla_put_u8(skb, DCB_ATTR_DCBX, dcbx); | ||
1490 | if (err) | ||
1491 | goto nla_put_failure; | ||
1492 | } | ||
1493 | return 0; | ||
1494 | |||
1495 | dcb_unlock: | ||
1496 | spin_unlock(&dcb_lock); | ||
1497 | nla_put_failure: | ||
1498 | return err; | ||
1499 | } | ||
1500 | |||
1501 | static int dcbnl_notify(struct net_device *dev, int event, int cmd, | ||
1502 | u32 seq, u32 pid, int dcbx_ver) | ||
1503 | { | ||
1504 | struct net *net = dev_net(dev); | ||
1505 | struct sk_buff *skb; | ||
1506 | struct nlmsghdr *nlh; | ||
1507 | struct dcbmsg *dcb; | ||
1508 | const struct dcbnl_rtnl_ops *ops = dev->dcbnl_ops; | ||
1509 | int err; | ||
1510 | |||
1511 | if (!ops) | ||
1512 | return -EOPNOTSUPP; | ||
1513 | |||
1514 | skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
1515 | if (!skb) | ||
1516 | return -ENOBUFS; | ||
1517 | |||
1518 | nlh = nlmsg_put(skb, pid, 0, event, sizeof(*dcb), 0); | ||
1519 | if (nlh == NULL) { | ||
1520 | nlmsg_free(skb); | ||
1521 | return -EMSGSIZE; | ||
1522 | } | ||
1523 | |||
1524 | dcb = NLMSG_DATA(nlh); | ||
1525 | dcb->dcb_family = AF_UNSPEC; | ||
1526 | dcb->cmd = cmd; | ||
1527 | |||
1528 | if (dcbx_ver == DCB_CAP_DCBX_VER_IEEE) | ||
1529 | err = dcbnl_ieee_fill(skb, dev); | ||
1530 | else | ||
1531 | err = dcbnl_cee_fill(skb, dev); | ||
1532 | |||
1533 | if (err < 0) { | ||
1534 | /* Report error to broadcast listeners */ | ||
1535 | nlmsg_cancel(skb, nlh); | ||
1536 | kfree_skb(skb); | ||
1537 | rtnl_set_sk_err(net, RTNLGRP_DCB, err); | ||
1538 | } else { | ||
1539 | /* End nlmsg and notify broadcast listeners */ | ||
1540 | nlmsg_end(skb, nlh); | ||
1541 | rtnl_notify(skb, net, 0, RTNLGRP_DCB, NULL, GFP_KERNEL); | ||
1542 | } | ||
1543 | |||
1544 | return err; | ||
1545 | } | ||
1546 | |||
1547 | int dcbnl_ieee_notify(struct net_device *dev, int event, int cmd, | ||
1548 | u32 seq, u32 pid) | ||
1549 | { | ||
1550 | return dcbnl_notify(dev, event, cmd, seq, pid, DCB_CAP_DCBX_VER_IEEE); | ||
1551 | } | ||
1552 | EXPORT_SYMBOL(dcbnl_ieee_notify); | ||
1553 | |||
1554 | int dcbnl_cee_notify(struct net_device *dev, int event, int cmd, | ||
1555 | u32 seq, u32 pid) | ||
1556 | { | ||
1557 | return dcbnl_notify(dev, event, cmd, seq, pid, DCB_CAP_DCBX_VER_CEE); | ||
1558 | } | ||
1559 | EXPORT_SYMBOL(dcbnl_cee_notify); | ||
1560 | |||
1561 | /* Handle IEEE 802.1Qaz SET commands. If any requested operation can not | ||
1562 | * be completed the entire msg is aborted and error value is returned. | ||
1563 | * No attempt is made to reconcile the case where only part of the | ||
1564 | * cmd can be completed. | ||
1565 | */ | ||
1566 | static int dcbnl_ieee_set(struct net_device *netdev, struct nlattr **tb, | ||
1567 | u32 pid, u32 seq, u16 flags) | ||
1568 | { | ||
1569 | const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; | ||
1570 | struct nlattr *ieee[DCB_ATTR_IEEE_MAX + 1]; | ||
1571 | int err = -EOPNOTSUPP; | ||
1572 | |||
1573 | if (!ops) | ||
1574 | return err; | ||
1575 | |||
1576 | if (!tb[DCB_ATTR_IEEE]) | ||
1577 | return -EINVAL; | ||
1578 | |||
1579 | err = nla_parse_nested(ieee, DCB_ATTR_IEEE_MAX, | ||
1580 | tb[DCB_ATTR_IEEE], dcbnl_ieee_policy); | ||
1581 | if (err) | ||
1582 | return err; | ||
1583 | |||
1584 | if (ieee[DCB_ATTR_IEEE_ETS] && ops->ieee_setets) { | ||
1585 | struct ieee_ets *ets = nla_data(ieee[DCB_ATTR_IEEE_ETS]); | ||
1586 | err = ops->ieee_setets(netdev, ets); | ||
1587 | if (err) | ||
1588 | goto err; | ||
1589 | } | ||
1590 | |||
1591 | if (ieee[DCB_ATTR_IEEE_PFC] && ops->ieee_setpfc) { | ||
1592 | struct ieee_pfc *pfc = nla_data(ieee[DCB_ATTR_IEEE_PFC]); | ||
1593 | err = ops->ieee_setpfc(netdev, pfc); | ||
1594 | if (err) | ||
1595 | goto err; | ||
1596 | } | ||
1597 | |||
1598 | if (ieee[DCB_ATTR_IEEE_APP_TABLE]) { | ||
1599 | struct nlattr *attr; | ||
1600 | int rem; | ||
1601 | |||
1602 | nla_for_each_nested(attr, ieee[DCB_ATTR_IEEE_APP_TABLE], rem) { | ||
1603 | struct dcb_app *app_data; | ||
1604 | if (nla_type(attr) != DCB_ATTR_IEEE_APP) | ||
1605 | continue; | ||
1606 | app_data = nla_data(attr); | ||
1607 | if (ops->ieee_setapp) | ||
1608 | err = ops->ieee_setapp(netdev, app_data); | ||
1609 | else | ||
1610 | err = dcb_ieee_setapp(netdev, app_data); | ||
1611 | if (err) | ||
1612 | goto err; | ||
1613 | } | ||
1614 | } | ||
1615 | |||
1616 | err: | ||
1617 | dcbnl_reply(err, RTM_SETDCB, DCB_CMD_IEEE_SET, DCB_ATTR_IEEE, | ||
1618 | pid, seq, flags); | ||
1619 | dcbnl_ieee_notify(netdev, RTM_SETDCB, DCB_CMD_IEEE_SET, seq, 0); | ||
1620 | return err; | ||
1621 | } | ||
1622 | |||
1623 | static int dcbnl_ieee_get(struct net_device *netdev, struct nlattr **tb, | ||
1624 | u32 pid, u32 seq, u16 flags) | ||
1625 | { | ||
1626 | struct net *net = dev_net(netdev); | ||
1627 | struct sk_buff *skb; | ||
1628 | struct nlmsghdr *nlh; | ||
1629 | struct dcbmsg *dcb; | ||
1630 | const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; | ||
1631 | int err; | ||
1632 | |||
1633 | if (!ops) | ||
1634 | return -EOPNOTSUPP; | ||
1635 | |||
1636 | skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
1637 | if (!skb) | ||
1638 | return -ENOBUFS; | ||
1639 | |||
1640 | nlh = nlmsg_put(skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); | ||
1641 | if (nlh == NULL) { | ||
1642 | nlmsg_free(skb); | ||
1643 | return -EMSGSIZE; | ||
1644 | } | ||
1645 | |||
1646 | dcb = NLMSG_DATA(nlh); | ||
1647 | dcb->dcb_family = AF_UNSPEC; | ||
1648 | dcb->cmd = DCB_CMD_IEEE_GET; | ||
1649 | |||
1650 | err = dcbnl_ieee_fill(skb, netdev); | ||
1651 | |||
1652 | if (err < 0) { | ||
1653 | nlmsg_cancel(skb, nlh); | ||
1654 | kfree_skb(skb); | ||
1655 | } else { | ||
1656 | nlmsg_end(skb, nlh); | ||
1657 | err = rtnl_unicast(skb, net, pid); | ||
1658 | } | ||
1659 | |||
1660 | return err; | ||
1661 | } | ||
1662 | |||
1663 | static int dcbnl_ieee_del(struct net_device *netdev, struct nlattr **tb, | ||
1664 | u32 pid, u32 seq, u16 flags) | ||
1665 | { | ||
1666 | const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; | ||
1667 | struct nlattr *ieee[DCB_ATTR_IEEE_MAX + 1]; | ||
1668 | int err = -EOPNOTSUPP; | ||
1669 | |||
1670 | if (!ops) | ||
1671 | return -EOPNOTSUPP; | ||
1672 | |||
1673 | if (!tb[DCB_ATTR_IEEE]) | ||
1674 | return -EINVAL; | ||
1675 | |||
1676 | err = nla_parse_nested(ieee, DCB_ATTR_IEEE_MAX, | ||
1677 | tb[DCB_ATTR_IEEE], dcbnl_ieee_policy); | ||
1678 | if (err) | ||
1679 | return err; | ||
1680 | |||
1681 | if (ieee[DCB_ATTR_IEEE_APP_TABLE]) { | ||
1682 | struct nlattr *attr; | ||
1683 | int rem; | ||
1684 | |||
1685 | nla_for_each_nested(attr, ieee[DCB_ATTR_IEEE_APP_TABLE], rem) { | ||
1686 | struct dcb_app *app_data; | ||
1687 | |||
1688 | if (nla_type(attr) != DCB_ATTR_IEEE_APP) | ||
1689 | continue; | ||
1690 | app_data = nla_data(attr); | ||
1691 | if (ops->ieee_delapp) | ||
1692 | err = ops->ieee_delapp(netdev, app_data); | ||
1693 | else | ||
1694 | err = dcb_ieee_delapp(netdev, app_data); | ||
1695 | if (err) | ||
1696 | goto err; | ||
1697 | } | ||
1698 | } | ||
1699 | |||
1700 | err: | ||
1701 | dcbnl_reply(err, RTM_SETDCB, DCB_CMD_IEEE_DEL, DCB_ATTR_IEEE, | ||
1702 | pid, seq, flags); | ||
1703 | dcbnl_ieee_notify(netdev, RTM_SETDCB, DCB_CMD_IEEE_DEL, seq, 0); | ||
1704 | return err; | ||
1705 | } | ||
1706 | |||
1707 | |||
1379 | /* DCBX configuration */ | 1708 | /* DCBX configuration */ |
1380 | static int dcbnl_getdcbx(struct net_device *netdev, struct nlattr **tb, | 1709 | static int dcbnl_getdcbx(struct net_device *netdev, struct nlattr **tb, |
1381 | u32 pid, u32 seq, u16 flags) | 1710 | u32 pid, u32 seq, u16 flags) |
@@ -1522,10 +1851,10 @@ err: | |||
1522 | static int dcbnl_cee_get(struct net_device *netdev, struct nlattr **tb, | 1851 | static int dcbnl_cee_get(struct net_device *netdev, struct nlattr **tb, |
1523 | u32 pid, u32 seq, u16 flags) | 1852 | u32 pid, u32 seq, u16 flags) |
1524 | { | 1853 | { |
1854 | struct net *net = dev_net(netdev); | ||
1525 | struct sk_buff *skb; | 1855 | struct sk_buff *skb; |
1526 | struct nlmsghdr *nlh; | 1856 | struct nlmsghdr *nlh; |
1527 | struct dcbmsg *dcb; | 1857 | struct dcbmsg *dcb; |
1528 | struct nlattr *cee; | ||
1529 | const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; | 1858 | const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; |
1530 | int err; | 1859 | int err; |
1531 | 1860 | ||
@@ -1536,51 +1865,26 @@ static int dcbnl_cee_get(struct net_device *netdev, struct nlattr **tb, | |||
1536 | if (!skb) | 1865 | if (!skb) |
1537 | return -ENOBUFS; | 1866 | return -ENOBUFS; |
1538 | 1867 | ||
1539 | nlh = NLMSG_NEW(skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); | 1868 | nlh = nlmsg_put(skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); |
1869 | if (nlh == NULL) { | ||
1870 | nlmsg_free(skb); | ||
1871 | return -EMSGSIZE; | ||
1872 | } | ||
1540 | 1873 | ||
1541 | dcb = NLMSG_DATA(nlh); | 1874 | dcb = NLMSG_DATA(nlh); |
1542 | dcb->dcb_family = AF_UNSPEC; | 1875 | dcb->dcb_family = AF_UNSPEC; |
1543 | dcb->cmd = DCB_CMD_CEE_GET; | 1876 | dcb->cmd = DCB_CMD_CEE_GET; |
1544 | 1877 | ||
1545 | NLA_PUT_STRING(skb, DCB_ATTR_IFNAME, netdev->name); | 1878 | err = dcbnl_cee_fill(skb, netdev); |
1546 | 1879 | ||
1547 | cee = nla_nest_start(skb, DCB_ATTR_CEE); | 1880 | if (err < 0) { |
1548 | if (!cee) | 1881 | nlmsg_cancel(skb, nlh); |
1549 | goto nla_put_failure; | 1882 | nlmsg_free(skb); |
1550 | 1883 | } else { | |
1551 | /* get peer info if available */ | 1884 | nlmsg_end(skb, nlh); |
1552 | if (ops->cee_peer_getpg) { | 1885 | err = rtnl_unicast(skb, net, pid); |
1553 | struct cee_pg pg; | ||
1554 | err = ops->cee_peer_getpg(netdev, &pg); | ||
1555 | if (!err) | ||
1556 | NLA_PUT(skb, DCB_ATTR_CEE_PEER_PG, sizeof(pg), &pg); | ||
1557 | } | ||
1558 | |||
1559 | if (ops->cee_peer_getpfc) { | ||
1560 | struct cee_pfc pfc; | ||
1561 | err = ops->cee_peer_getpfc(netdev, &pfc); | ||
1562 | if (!err) | ||
1563 | NLA_PUT(skb, DCB_ATTR_CEE_PEER_PFC, sizeof(pfc), &pfc); | ||
1564 | } | ||
1565 | |||
1566 | if (ops->peer_getappinfo && ops->peer_getapptable) { | ||
1567 | err = dcbnl_build_peer_app(netdev, skb, | ||
1568 | DCB_ATTR_CEE_PEER_APP_TABLE, | ||
1569 | DCB_ATTR_CEE_PEER_APP_INFO, | ||
1570 | DCB_ATTR_CEE_PEER_APP); | ||
1571 | if (err) | ||
1572 | goto nla_put_failure; | ||
1573 | } | 1886 | } |
1574 | 1887 | return err; | |
1575 | nla_nest_end(skb, cee); | ||
1576 | nlmsg_end(skb, nlh); | ||
1577 | |||
1578 | return rtnl_unicast(skb, &init_net, pid); | ||
1579 | nla_put_failure: | ||
1580 | nlmsg_cancel(skb, nlh); | ||
1581 | nlmsg_failure: | ||
1582 | kfree_skb(skb); | ||
1583 | return -1; | ||
1584 | } | 1888 | } |
1585 | 1889 | ||
1586 | static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | 1890 | static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) |
@@ -1690,11 +1994,15 @@ static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
1690 | goto out; | 1994 | goto out; |
1691 | case DCB_CMD_IEEE_SET: | 1995 | case DCB_CMD_IEEE_SET: |
1692 | ret = dcbnl_ieee_set(netdev, tb, pid, nlh->nlmsg_seq, | 1996 | ret = dcbnl_ieee_set(netdev, tb, pid, nlh->nlmsg_seq, |
1693 | nlh->nlmsg_flags); | 1997 | nlh->nlmsg_flags); |
1694 | goto out; | 1998 | goto out; |
1695 | case DCB_CMD_IEEE_GET: | 1999 | case DCB_CMD_IEEE_GET: |
1696 | ret = dcbnl_ieee_get(netdev, tb, pid, nlh->nlmsg_seq, | 2000 | ret = dcbnl_ieee_get(netdev, tb, pid, nlh->nlmsg_seq, |
1697 | nlh->nlmsg_flags); | 2001 | nlh->nlmsg_flags); |
2002 | goto out; | ||
2003 | case DCB_CMD_IEEE_DEL: | ||
2004 | ret = dcbnl_ieee_del(netdev, tb, pid, nlh->nlmsg_seq, | ||
2005 | nlh->nlmsg_flags); | ||
1698 | goto out; | 2006 | goto out; |
1699 | case DCB_CMD_GDCBX: | 2007 | case DCB_CMD_GDCBX: |
1700 | ret = dcbnl_getdcbx(netdev, tb, pid, nlh->nlmsg_seq, | 2008 | ret = dcbnl_getdcbx(netdev, tb, pid, nlh->nlmsg_seq, |
@@ -1754,12 +2062,13 @@ u8 dcb_getapp(struct net_device *dev, struct dcb_app *app) | |||
1754 | EXPORT_SYMBOL(dcb_getapp); | 2062 | EXPORT_SYMBOL(dcb_getapp); |
1755 | 2063 | ||
1756 | /** | 2064 | /** |
1757 | * ixgbe_dcbnl_setapp - add dcb application data to app list | 2065 | * dcb_setapp - add CEE dcb application data to app list |
1758 | * | 2066 | * |
1759 | * Priority 0 is the default priority this removes applications | 2067 | * Priority 0 is an invalid priority in CEE spec. This routine |
1760 | * from the app list if the priority is set to zero. | 2068 | * removes applications from the app list if the priority is |
2069 | * set to zero. | ||
1761 | */ | 2070 | */ |
1762 | u8 dcb_setapp(struct net_device *dev, struct dcb_app *new) | 2071 | int dcb_setapp(struct net_device *dev, struct dcb_app *new) |
1763 | { | 2072 | { |
1764 | struct dcb_app_type *itr; | 2073 | struct dcb_app_type *itr; |
1765 | struct dcb_app_type event; | 2074 | struct dcb_app_type event; |
@@ -1802,6 +2111,114 @@ out: | |||
1802 | } | 2111 | } |
1803 | EXPORT_SYMBOL(dcb_setapp); | 2112 | EXPORT_SYMBOL(dcb_setapp); |
1804 | 2113 | ||
2114 | /** | ||
2115 | * dcb_ieee_getapp_mask - retrieve the IEEE DCB application priority | ||
2116 | * | ||
2117 | * Helper routine which on success returns a non-zero 802.1Qaz user | ||
2118 | * priority bitmap otherwise returns 0 to indicate the dcb_app was | ||
2119 | * not found in APP list. | ||
2120 | */ | ||
2121 | u8 dcb_ieee_getapp_mask(struct net_device *dev, struct dcb_app *app) | ||
2122 | { | ||
2123 | struct dcb_app_type *itr; | ||
2124 | u8 prio = 0; | ||
2125 | |||
2126 | spin_lock(&dcb_lock); | ||
2127 | list_for_each_entry(itr, &dcb_app_list, list) { | ||
2128 | if (itr->app.selector == app->selector && | ||
2129 | itr->app.protocol == app->protocol && | ||
2130 | (strncmp(itr->name, dev->name, IFNAMSIZ) == 0)) { | ||
2131 | prio |= 1 << itr->app.priority; | ||
2132 | } | ||
2133 | } | ||
2134 | spin_unlock(&dcb_lock); | ||
2135 | |||
2136 | return prio; | ||
2137 | } | ||
2138 | EXPORT_SYMBOL(dcb_ieee_getapp_mask); | ||
2139 | |||
2140 | /** | ||
2141 | * dcb_ieee_setapp - add IEEE dcb application data to app list | ||
2142 | * | ||
2143 | * This adds Application data to the list. Multiple application | ||
2144 | * entries may exists for the same selector and protocol as long | ||
2145 | * as the priorities are different. | ||
2146 | */ | ||
2147 | int dcb_ieee_setapp(struct net_device *dev, struct dcb_app *new) | ||
2148 | { | ||
2149 | struct dcb_app_type *itr, *entry; | ||
2150 | struct dcb_app_type event; | ||
2151 | int err = 0; | ||
2152 | |||
2153 | memcpy(&event.name, dev->name, sizeof(event.name)); | ||
2154 | memcpy(&event.app, new, sizeof(event.app)); | ||
2155 | |||
2156 | spin_lock(&dcb_lock); | ||
2157 | /* Search for existing match and abort if found */ | ||
2158 | list_for_each_entry(itr, &dcb_app_list, list) { | ||
2159 | if (itr->app.selector == new->selector && | ||
2160 | itr->app.protocol == new->protocol && | ||
2161 | itr->app.priority == new->priority && | ||
2162 | (strncmp(itr->name, dev->name, IFNAMSIZ) == 0)) { | ||
2163 | err = -EEXIST; | ||
2164 | goto out; | ||
2165 | } | ||
2166 | } | ||
2167 | |||
2168 | /* App entry does not exist add new entry */ | ||
2169 | entry = kmalloc(sizeof(struct dcb_app_type), GFP_ATOMIC); | ||
2170 | if (!entry) { | ||
2171 | err = -ENOMEM; | ||
2172 | goto out; | ||
2173 | } | ||
2174 | |||
2175 | memcpy(&entry->app, new, sizeof(*new)); | ||
2176 | strncpy(entry->name, dev->name, IFNAMSIZ); | ||
2177 | list_add(&entry->list, &dcb_app_list); | ||
2178 | out: | ||
2179 | spin_unlock(&dcb_lock); | ||
2180 | if (!err) | ||
2181 | call_dcbevent_notifiers(DCB_APP_EVENT, &event); | ||
2182 | return err; | ||
2183 | } | ||
2184 | EXPORT_SYMBOL(dcb_ieee_setapp); | ||
2185 | |||
2186 | /** | ||
2187 | * dcb_ieee_delapp - delete IEEE dcb application data from list | ||
2188 | * | ||
2189 | * This removes a matching APP data from the APP list | ||
2190 | */ | ||
2191 | int dcb_ieee_delapp(struct net_device *dev, struct dcb_app *del) | ||
2192 | { | ||
2193 | struct dcb_app_type *itr; | ||
2194 | struct dcb_app_type event; | ||
2195 | int err = -ENOENT; | ||
2196 | |||
2197 | memcpy(&event.name, dev->name, sizeof(event.name)); | ||
2198 | memcpy(&event.app, del, sizeof(event.app)); | ||
2199 | |||
2200 | spin_lock(&dcb_lock); | ||
2201 | /* Search for existing match and remove it. */ | ||
2202 | list_for_each_entry(itr, &dcb_app_list, list) { | ||
2203 | if (itr->app.selector == del->selector && | ||
2204 | itr->app.protocol == del->protocol && | ||
2205 | itr->app.priority == del->priority && | ||
2206 | (strncmp(itr->name, dev->name, IFNAMSIZ) == 0)) { | ||
2207 | list_del(&itr->list); | ||
2208 | kfree(itr); | ||
2209 | err = 0; | ||
2210 | goto out; | ||
2211 | } | ||
2212 | } | ||
2213 | |||
2214 | out: | ||
2215 | spin_unlock(&dcb_lock); | ||
2216 | if (!err) | ||
2217 | call_dcbevent_notifiers(DCB_APP_EVENT, &event); | ||
2218 | return err; | ||
2219 | } | ||
2220 | EXPORT_SYMBOL(dcb_ieee_delapp); | ||
2221 | |||
1805 | static void dcb_flushapp(void) | 2222 | static void dcb_flushapp(void) |
1806 | { | 2223 | { |
1807 | struct dcb_app_type *app; | 2224 | struct dcb_app_type *app; |
@@ -1819,8 +2236,8 @@ static int __init dcbnl_init(void) | |||
1819 | { | 2236 | { |
1820 | INIT_LIST_HEAD(&dcb_app_list); | 2237 | INIT_LIST_HEAD(&dcb_app_list); |
1821 | 2238 | ||
1822 | rtnl_register(PF_UNSPEC, RTM_GETDCB, dcb_doit, NULL); | 2239 | rtnl_register(PF_UNSPEC, RTM_GETDCB, dcb_doit, NULL, NULL); |
1823 | rtnl_register(PF_UNSPEC, RTM_SETDCB, dcb_doit, NULL); | 2240 | rtnl_register(PF_UNSPEC, RTM_SETDCB, dcb_doit, NULL, NULL); |
1824 | 2241 | ||
1825 | return 0; | 2242 | return 0; |
1826 | } | 2243 | } |