diff options
author | John Fastabend <john.r.fastabend@intel.com> | 2010-12-30 04:26:31 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-12-31 13:47:45 -0500 |
commit | 9ab933ab2cc80f04690d6aa385b1110075c5e507 (patch) | |
tree | 439f1d393d080473575f5ecfe6dcd4f3c10775e9 /net/dcb/dcbnl.c | |
parent | 3e29027af43728c2a91fe3f735ab2822edaf54a8 (diff) |
dcbnl: add appliction tlv handlers
This patch adds application tlv handlers. Networking stacks
may use the application priority to set the skb priority of
their stack using the negoatiated dcbx priority.
This patch provides the dcb_{get|set}app() routines for the
stack to query these parameters. Notice lower layer drivers
can use the dcbnl_ops routines if additional handling is
needed. Perhaps in the firmware case for example
Signed-off-by: John Fastabend <john.r.fastabend@intel.com>
Signed-off-by: Shmulik Ravid <shmulikr@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/dcb/dcbnl.c')
-rw-r--r-- | net/dcb/dcbnl.c | 133 |
1 files changed, 123 insertions, 10 deletions
diff --git a/net/dcb/dcbnl.c b/net/dcb/dcbnl.c index 2ff908498924..cfd731faf6c6 100644 --- a/net/dcb/dcbnl.c +++ b/net/dcb/dcbnl.c | |||
@@ -179,6 +179,9 @@ static const struct nla_policy dcbnl_ieee_app[DCB_ATTR_IEEE_APP_MAX + 1] = { | |||
179 | [DCB_ATTR_IEEE_APP] = {.len = sizeof(struct dcb_app)}, | 179 | [DCB_ATTR_IEEE_APP] = {.len = sizeof(struct dcb_app)}, |
180 | }; | 180 | }; |
181 | 181 | ||
182 | static LIST_HEAD(dcb_app_list); | ||
183 | static DEFINE_SPINLOCK(dcb_lock); | ||
184 | |||
182 | /* standard netlink reply call */ | 185 | /* standard netlink reply call */ |
183 | static int dcbnl_reply(u8 value, u8 event, u8 cmd, u8 attr, u32 pid, | 186 | static int dcbnl_reply(u8 value, u8 event, u8 cmd, u8 attr, u32 pid, |
184 | u32 seq, u16 flags) | 187 | u32 seq, u16 flags) |
@@ -634,12 +637,12 @@ out: | |||
634 | static int dcbnl_setapp(struct net_device *netdev, struct nlattr **tb, | 637 | static int dcbnl_setapp(struct net_device *netdev, struct nlattr **tb, |
635 | u32 pid, u32 seq, u16 flags) | 638 | u32 pid, u32 seq, u16 flags) |
636 | { | 639 | { |
637 | int ret = -EINVAL; | 640 | int err, ret = -EINVAL; |
638 | u16 id; | 641 | u16 id; |
639 | u8 up, idtype; | 642 | u8 up, idtype; |
640 | struct nlattr *app_tb[DCB_APP_ATTR_MAX + 1]; | 643 | struct nlattr *app_tb[DCB_APP_ATTR_MAX + 1]; |
641 | 644 | ||
642 | if (!tb[DCB_ATTR_APP] || !netdev->dcbnl_ops->setapp) | 645 | if (!tb[DCB_ATTR_APP]) |
643 | goto out; | 646 | goto out; |
644 | 647 | ||
645 | ret = nla_parse_nested(app_tb, DCB_APP_ATTR_MAX, tb[DCB_ATTR_APP], | 648 | ret = nla_parse_nested(app_tb, DCB_APP_ATTR_MAX, tb[DCB_ATTR_APP], |
@@ -663,9 +666,18 @@ static int dcbnl_setapp(struct net_device *netdev, struct nlattr **tb, | |||
663 | id = nla_get_u16(app_tb[DCB_APP_ATTR_ID]); | 666 | id = nla_get_u16(app_tb[DCB_APP_ATTR_ID]); |
664 | up = nla_get_u8(app_tb[DCB_APP_ATTR_PRIORITY]); | 667 | up = nla_get_u8(app_tb[DCB_APP_ATTR_PRIORITY]); |
665 | 668 | ||
666 | ret = dcbnl_reply(netdev->dcbnl_ops->setapp(netdev, idtype, id, up), | 669 | if (netdev->dcbnl_ops->setapp) { |
667 | RTM_SETDCB, DCB_CMD_SAPP, DCB_ATTR_APP, | 670 | err = netdev->dcbnl_ops->setapp(netdev, idtype, id, up); |
668 | pid, seq, flags); | 671 | } else { |
672 | struct dcb_app app; | ||
673 | app.selector = idtype; | ||
674 | app.protocol = id; | ||
675 | app.priority = up; | ||
676 | err = dcb_setapp(netdev, &app); | ||
677 | } | ||
678 | |||
679 | ret = dcbnl_reply(err, RTM_SETDCB, DCB_CMD_SAPP, DCB_ATTR_APP, | ||
680 | pid, seq, flags); | ||
669 | out: | 681 | out: |
670 | return ret; | 682 | return ret; |
671 | } | 683 | } |
@@ -1164,7 +1176,7 @@ static int dcbnl_ieee_set(struct net_device *netdev, struct nlattr **tb, | |||
1164 | goto err; | 1176 | goto err; |
1165 | } | 1177 | } |
1166 | 1178 | ||
1167 | if (ieee[DCB_ATTR_IEEE_APP_TABLE] && ops->ieee_setapp) { | 1179 | if (ieee[DCB_ATTR_IEEE_APP_TABLE]) { |
1168 | struct nlattr *attr; | 1180 | struct nlattr *attr; |
1169 | int rem; | 1181 | int rem; |
1170 | 1182 | ||
@@ -1173,7 +1185,10 @@ static int dcbnl_ieee_set(struct net_device *netdev, struct nlattr **tb, | |||
1173 | if (nla_type(attr) != DCB_ATTR_IEEE_APP) | 1185 | if (nla_type(attr) != DCB_ATTR_IEEE_APP) |
1174 | continue; | 1186 | continue; |
1175 | app_data = nla_data(attr); | 1187 | app_data = nla_data(attr); |
1176 | err = ops->ieee_setapp(netdev, app_data); | 1188 | if (ops->ieee_setapp) |
1189 | err = ops->ieee_setapp(netdev, app_data); | ||
1190 | else | ||
1191 | err = dcb_setapp(netdev, app_data); | ||
1177 | if (err) | 1192 | if (err) |
1178 | goto err; | 1193 | goto err; |
1179 | } | 1194 | } |
@@ -1193,7 +1208,8 @@ static int dcbnl_ieee_get(struct net_device *netdev, struct nlattr **tb, | |||
1193 | struct sk_buff *skb; | 1208 | struct sk_buff *skb; |
1194 | struct nlmsghdr *nlh; | 1209 | struct nlmsghdr *nlh; |
1195 | struct dcbmsg *dcb; | 1210 | struct dcbmsg *dcb; |
1196 | struct nlattr *ieee; | 1211 | struct nlattr *ieee, *app; |
1212 | struct dcb_app_type *itr; | ||
1197 | const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; | 1213 | const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; |
1198 | int err; | 1214 | int err; |
1199 | 1215 | ||
@@ -1230,6 +1246,19 @@ static int dcbnl_ieee_get(struct net_device *netdev, struct nlattr **tb, | |||
1230 | NLA_PUT(skb, DCB_ATTR_IEEE_PFC, sizeof(pfc), &pfc); | 1246 | NLA_PUT(skb, DCB_ATTR_IEEE_PFC, sizeof(pfc), &pfc); |
1231 | } | 1247 | } |
1232 | 1248 | ||
1249 | app = nla_nest_start(skb, DCB_ATTR_IEEE_APP_TABLE); | ||
1250 | if (!app) | ||
1251 | goto nla_put_failure; | ||
1252 | |||
1253 | spin_lock(&dcb_lock); | ||
1254 | list_for_each_entry(itr, &dcb_app_list, list) { | ||
1255 | if (strncmp(itr->name, netdev->name, IFNAMSIZ) == 0) | ||
1256 | NLA_PUT(skb, DCB_ATTR_IEEE_APP, | ||
1257 | sizeof(itr->app), &itr->app); | ||
1258 | } | ||
1259 | spin_unlock(&dcb_lock); | ||
1260 | nla_nest_end(skb, app); | ||
1261 | |||
1233 | nla_nest_end(skb, ieee); | 1262 | nla_nest_end(skb, ieee); |
1234 | nlmsg_end(skb, nlh); | 1263 | nlmsg_end(skb, nlh); |
1235 | 1264 | ||
@@ -1364,8 +1393,93 @@ out: | |||
1364 | return ret; | 1393 | return ret; |
1365 | } | 1394 | } |
1366 | 1395 | ||
1396 | /** | ||
1397 | * dcb_getapp - retrieve the DCBX application user priority | ||
1398 | * | ||
1399 | * On success returns a non-zero 802.1p user priority bitmap | ||
1400 | * otherwise returns 0 as the invalid user priority bitmap to | ||
1401 | * indicate an error. | ||
1402 | */ | ||
1403 | u8 dcb_getapp(struct net_device *dev, struct dcb_app *app) | ||
1404 | { | ||
1405 | struct dcb_app_type *itr; | ||
1406 | u8 prio = 0; | ||
1407 | |||
1408 | spin_lock(&dcb_lock); | ||
1409 | list_for_each_entry(itr, &dcb_app_list, list) { | ||
1410 | if (itr->app.selector == app->selector && | ||
1411 | itr->app.protocol == app->protocol && | ||
1412 | (strncmp(itr->name, dev->name, IFNAMSIZ) == 0)) { | ||
1413 | prio = itr->app.priority; | ||
1414 | break; | ||
1415 | } | ||
1416 | } | ||
1417 | spin_unlock(&dcb_lock); | ||
1418 | |||
1419 | return prio; | ||
1420 | } | ||
1421 | EXPORT_SYMBOL(dcb_getapp); | ||
1422 | |||
1423 | /** | ||
1424 | * ixgbe_dcbnl_setapp - add dcb application data to app list | ||
1425 | * | ||
1426 | * Priority 0 is the default priority this removes applications | ||
1427 | * from the app list if the priority is set to zero. | ||
1428 | */ | ||
1429 | u8 dcb_setapp(struct net_device *dev, struct dcb_app *new) | ||
1430 | { | ||
1431 | struct dcb_app_type *itr; | ||
1432 | |||
1433 | spin_lock(&dcb_lock); | ||
1434 | /* Search for existing match and replace */ | ||
1435 | list_for_each_entry(itr, &dcb_app_list, list) { | ||
1436 | if (itr->app.selector == new->selector && | ||
1437 | itr->app.protocol == new->protocol && | ||
1438 | (strncmp(itr->name, dev->name, IFNAMSIZ) == 0)) { | ||
1439 | if (new->priority) | ||
1440 | itr->app.priority = new->priority; | ||
1441 | else { | ||
1442 | list_del(&itr->list); | ||
1443 | kfree(itr); | ||
1444 | } | ||
1445 | goto out; | ||
1446 | } | ||
1447 | } | ||
1448 | /* App type does not exist add new application type */ | ||
1449 | if (new->priority) { | ||
1450 | struct dcb_app_type *entry; | ||
1451 | entry = kmalloc(sizeof(struct dcb_app_type), GFP_ATOMIC); | ||
1452 | if (!entry) { | ||
1453 | spin_unlock(&dcb_lock); | ||
1454 | return -ENOMEM; | ||
1455 | } | ||
1456 | |||
1457 | memcpy(&entry->app, new, sizeof(*new)); | ||
1458 | strncpy(entry->name, dev->name, IFNAMSIZ); | ||
1459 | list_add(&entry->list, &dcb_app_list); | ||
1460 | } | ||
1461 | out: | ||
1462 | spin_unlock(&dcb_lock); | ||
1463 | return 0; | ||
1464 | } | ||
1465 | EXPORT_SYMBOL(dcb_setapp); | ||
1466 | |||
1467 | void dcb_flushapp(void) | ||
1468 | { | ||
1469 | struct dcb_app_type *app; | ||
1470 | |||
1471 | spin_lock(&dcb_lock); | ||
1472 | list_for_each_entry(app, &dcb_app_list, list) { | ||
1473 | list_del(&app->list); | ||
1474 | kfree(app); | ||
1475 | } | ||
1476 | spin_unlock(&dcb_lock); | ||
1477 | } | ||
1478 | |||
1367 | static int __init dcbnl_init(void) | 1479 | static int __init dcbnl_init(void) |
1368 | { | 1480 | { |
1481 | INIT_LIST_HEAD(&dcb_app_list); | ||
1482 | |||
1369 | rtnl_register(PF_UNSPEC, RTM_GETDCB, dcb_doit, NULL); | 1483 | rtnl_register(PF_UNSPEC, RTM_GETDCB, dcb_doit, NULL); |
1370 | rtnl_register(PF_UNSPEC, RTM_SETDCB, dcb_doit, NULL); | 1484 | rtnl_register(PF_UNSPEC, RTM_SETDCB, dcb_doit, NULL); |
1371 | 1485 | ||
@@ -1377,7 +1491,6 @@ static void __exit dcbnl_exit(void) | |||
1377 | { | 1491 | { |
1378 | rtnl_unregister(PF_UNSPEC, RTM_GETDCB); | 1492 | rtnl_unregister(PF_UNSPEC, RTM_GETDCB); |
1379 | rtnl_unregister(PF_UNSPEC, RTM_SETDCB); | 1493 | rtnl_unregister(PF_UNSPEC, RTM_SETDCB); |
1494 | dcb_flushapp(); | ||
1380 | } | 1495 | } |
1381 | module_exit(dcbnl_exit); | 1496 | module_exit(dcbnl_exit); |
1382 | |||
1383 | |||