diff options
Diffstat (limited to 'net/dcb/dcbnl.c')
-rw-r--r-- | net/dcb/dcbnl.c | 429 |
1 files changed, 422 insertions, 7 deletions
diff --git a/net/dcb/dcbnl.c b/net/dcb/dcbnl.c index 19ac2b985485..9399af565715 100644 --- a/net/dcb/dcbnl.c +++ b/net/dcb/dcbnl.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <net/netlink.h> | 23 | #include <net/netlink.h> |
24 | #include <net/rtnetlink.h> | 24 | #include <net/rtnetlink.h> |
25 | #include <linux/dcbnl.h> | 25 | #include <linux/dcbnl.h> |
26 | #include <net/dcbevent.h> | ||
26 | #include <linux/rtnetlink.h> | 27 | #include <linux/rtnetlink.h> |
27 | #include <net/sock.h> | 28 | #include <net/sock.h> |
28 | 29 | ||
@@ -66,6 +67,9 @@ static const struct nla_policy dcbnl_rtnl_policy[DCB_ATTR_MAX + 1] = { | |||
66 | [DCB_ATTR_PFC_STATE] = {.type = NLA_U8}, | 67 | [DCB_ATTR_PFC_STATE] = {.type = NLA_U8}, |
67 | [DCB_ATTR_BCN] = {.type = NLA_NESTED}, | 68 | [DCB_ATTR_BCN] = {.type = NLA_NESTED}, |
68 | [DCB_ATTR_APP] = {.type = NLA_NESTED}, | 69 | [DCB_ATTR_APP] = {.type = NLA_NESTED}, |
70 | [DCB_ATTR_IEEE] = {.type = NLA_NESTED}, | ||
71 | [DCB_ATTR_DCBX] = {.type = NLA_U8}, | ||
72 | [DCB_ATTR_FEATCFG] = {.type = NLA_NESTED}, | ||
69 | }; | 73 | }; |
70 | 74 | ||
71 | /* DCB priority flow control to User Priority nested attributes */ | 75 | /* DCB priority flow control to User Priority nested attributes */ |
@@ -122,6 +126,7 @@ static const struct nla_policy dcbnl_cap_nest[DCB_CAP_ATTR_MAX + 1] = { | |||
122 | [DCB_CAP_ATTR_PFC_TCS] = {.type = NLA_U8}, | 126 | [DCB_CAP_ATTR_PFC_TCS] = {.type = NLA_U8}, |
123 | [DCB_CAP_ATTR_GSP] = {.type = NLA_U8}, | 127 | [DCB_CAP_ATTR_GSP] = {.type = NLA_U8}, |
124 | [DCB_CAP_ATTR_BCN] = {.type = NLA_U8}, | 128 | [DCB_CAP_ATTR_BCN] = {.type = NLA_U8}, |
129 | [DCB_CAP_ATTR_DCBX] = {.type = NLA_U8}, | ||
125 | }; | 130 | }; |
126 | 131 | ||
127 | /* DCB capabilities nested attributes. */ | 132 | /* DCB capabilities nested attributes. */ |
@@ -167,6 +172,28 @@ static const struct nla_policy dcbnl_app_nest[DCB_APP_ATTR_MAX + 1] = { | |||
167 | [DCB_APP_ATTR_PRIORITY] = {.type = NLA_U8}, | 172 | [DCB_APP_ATTR_PRIORITY] = {.type = NLA_U8}, |
168 | }; | 173 | }; |
169 | 174 | ||
175 | /* IEEE 802.1Qaz nested attributes. */ | ||
176 | static const struct nla_policy dcbnl_ieee_policy[DCB_ATTR_IEEE_MAX + 1] = { | ||
177 | [DCB_ATTR_IEEE_ETS] = {.len = sizeof(struct ieee_ets)}, | ||
178 | [DCB_ATTR_IEEE_PFC] = {.len = sizeof(struct ieee_pfc)}, | ||
179 | [DCB_ATTR_IEEE_APP_TABLE] = {.type = NLA_NESTED}, | ||
180 | }; | ||
181 | |||
182 | static const struct nla_policy dcbnl_ieee_app[DCB_ATTR_IEEE_APP_MAX + 1] = { | ||
183 | [DCB_ATTR_IEEE_APP] = {.len = sizeof(struct dcb_app)}, | ||
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 | |||
194 | static LIST_HEAD(dcb_app_list); | ||
195 | static DEFINE_SPINLOCK(dcb_lock); | ||
196 | |||
170 | /* standard netlink reply call */ | 197 | /* standard netlink reply call */ |
171 | static int dcbnl_reply(u8 value, u8 event, u8 cmd, u8 attr, u32 pid, | 198 | static int dcbnl_reply(u8 value, u8 event, u8 cmd, u8 attr, u32 pid, |
172 | u32 seq, u16 flags) | 199 | u32 seq, u16 flags) |
@@ -622,12 +649,12 @@ out: | |||
622 | static int dcbnl_setapp(struct net_device *netdev, struct nlattr **tb, | 649 | static int dcbnl_setapp(struct net_device *netdev, struct nlattr **tb, |
623 | u32 pid, u32 seq, u16 flags) | 650 | u32 pid, u32 seq, u16 flags) |
624 | { | 651 | { |
625 | int ret = -EINVAL; | 652 | int err, ret = -EINVAL; |
626 | u16 id; | 653 | u16 id; |
627 | u8 up, idtype; | 654 | u8 up, idtype; |
628 | struct nlattr *app_tb[DCB_APP_ATTR_MAX + 1]; | 655 | struct nlattr *app_tb[DCB_APP_ATTR_MAX + 1]; |
629 | 656 | ||
630 | if (!tb[DCB_ATTR_APP] || !netdev->dcbnl_ops->setapp) | 657 | if (!tb[DCB_ATTR_APP]) |
631 | goto out; | 658 | goto out; |
632 | 659 | ||
633 | ret = nla_parse_nested(app_tb, DCB_APP_ATTR_MAX, tb[DCB_ATTR_APP], | 660 | ret = nla_parse_nested(app_tb, DCB_APP_ATTR_MAX, tb[DCB_ATTR_APP], |
@@ -651,9 +678,18 @@ static int dcbnl_setapp(struct net_device *netdev, struct nlattr **tb, | |||
651 | id = nla_get_u16(app_tb[DCB_APP_ATTR_ID]); | 678 | id = nla_get_u16(app_tb[DCB_APP_ATTR_ID]); |
652 | up = nla_get_u8(app_tb[DCB_APP_ATTR_PRIORITY]); | 679 | up = nla_get_u8(app_tb[DCB_APP_ATTR_PRIORITY]); |
653 | 680 | ||
654 | ret = dcbnl_reply(netdev->dcbnl_ops->setapp(netdev, idtype, id, up), | 681 | if (netdev->dcbnl_ops->setapp) { |
655 | RTM_SETDCB, DCB_CMD_SAPP, DCB_ATTR_APP, | 682 | err = netdev->dcbnl_ops->setapp(netdev, idtype, id, up); |
656 | pid, seq, flags); | 683 | } else { |
684 | struct dcb_app app; | ||
685 | app.selector = idtype; | ||
686 | app.protocol = id; | ||
687 | app.priority = up; | ||
688 | err = dcb_setapp(netdev, &app); | ||
689 | } | ||
690 | |||
691 | ret = dcbnl_reply(err, RTM_SETDCB, DCB_CMD_SAPP, DCB_ATTR_APP, | ||
692 | pid, seq, flags); | ||
657 | out: | 693 | out: |
658 | return ret; | 694 | return ret; |
659 | } | 695 | } |
@@ -1118,6 +1154,276 @@ err: | |||
1118 | return ret; | 1154 | return ret; |
1119 | } | 1155 | } |
1120 | 1156 | ||
1157 | /* Handle IEEE 802.1Qaz SET commands. If any requested operation can not | ||
1158 | * be completed the entire msg is aborted and error value is returned. | ||
1159 | * No attempt is made to reconcile the case where only part of the | ||
1160 | * cmd can be completed. | ||
1161 | */ | ||
1162 | static int dcbnl_ieee_set(struct net_device *netdev, struct nlattr **tb, | ||
1163 | u32 pid, u32 seq, u16 flags) | ||
1164 | { | ||
1165 | const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; | ||
1166 | struct nlattr *ieee[DCB_ATTR_IEEE_MAX + 1]; | ||
1167 | int err = -EOPNOTSUPP; | ||
1168 | |||
1169 | if (!ops) | ||
1170 | goto err; | ||
1171 | |||
1172 | err = nla_parse_nested(ieee, DCB_ATTR_IEEE_MAX, | ||
1173 | tb[DCB_ATTR_IEEE], dcbnl_ieee_policy); | ||
1174 | if (err) | ||
1175 | goto err; | ||
1176 | |||
1177 | if (ieee[DCB_ATTR_IEEE_ETS] && ops->ieee_setets) { | ||
1178 | struct ieee_ets *ets = nla_data(ieee[DCB_ATTR_IEEE_ETS]); | ||
1179 | err = ops->ieee_setets(netdev, ets); | ||
1180 | if (err) | ||
1181 | goto err; | ||
1182 | } | ||
1183 | |||
1184 | if (ieee[DCB_ATTR_IEEE_PFC] && ops->ieee_setets) { | ||
1185 | struct ieee_pfc *pfc = nla_data(ieee[DCB_ATTR_IEEE_PFC]); | ||
1186 | err = ops->ieee_setpfc(netdev, pfc); | ||
1187 | if (err) | ||
1188 | goto err; | ||
1189 | } | ||
1190 | |||
1191 | if (ieee[DCB_ATTR_IEEE_APP_TABLE]) { | ||
1192 | struct nlattr *attr; | ||
1193 | int rem; | ||
1194 | |||
1195 | nla_for_each_nested(attr, ieee[DCB_ATTR_IEEE_APP_TABLE], rem) { | ||
1196 | struct dcb_app *app_data; | ||
1197 | if (nla_type(attr) != DCB_ATTR_IEEE_APP) | ||
1198 | continue; | ||
1199 | app_data = nla_data(attr); | ||
1200 | if (ops->ieee_setapp) | ||
1201 | err = ops->ieee_setapp(netdev, app_data); | ||
1202 | else | ||
1203 | err = dcb_setapp(netdev, app_data); | ||
1204 | if (err) | ||
1205 | goto err; | ||
1206 | } | ||
1207 | } | ||
1208 | |||
1209 | err: | ||
1210 | dcbnl_reply(err, RTM_SETDCB, DCB_CMD_IEEE_SET, DCB_ATTR_IEEE, | ||
1211 | pid, seq, flags); | ||
1212 | return err; | ||
1213 | } | ||
1214 | |||
1215 | |||
1216 | /* Handle IEEE 802.1Qaz GET commands. */ | ||
1217 | static int dcbnl_ieee_get(struct net_device *netdev, struct nlattr **tb, | ||
1218 | u32 pid, u32 seq, u16 flags) | ||
1219 | { | ||
1220 | struct sk_buff *skb; | ||
1221 | struct nlmsghdr *nlh; | ||
1222 | struct dcbmsg *dcb; | ||
1223 | struct nlattr *ieee, *app; | ||
1224 | struct dcb_app_type *itr; | ||
1225 | const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; | ||
1226 | int err; | ||
1227 | |||
1228 | if (!ops) | ||
1229 | return -EOPNOTSUPP; | ||
1230 | |||
1231 | skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
1232 | if (!skb) | ||
1233 | return -ENOBUFS; | ||
1234 | |||
1235 | nlh = NLMSG_NEW(skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); | ||
1236 | |||
1237 | dcb = NLMSG_DATA(nlh); | ||
1238 | dcb->dcb_family = AF_UNSPEC; | ||
1239 | dcb->cmd = DCB_CMD_IEEE_GET; | ||
1240 | |||
1241 | NLA_PUT_STRING(skb, DCB_ATTR_IFNAME, netdev->name); | ||
1242 | |||
1243 | ieee = nla_nest_start(skb, DCB_ATTR_IEEE); | ||
1244 | if (!ieee) | ||
1245 | goto nla_put_failure; | ||
1246 | |||
1247 | if (ops->ieee_getets) { | ||
1248 | struct ieee_ets ets; | ||
1249 | err = ops->ieee_getets(netdev, &ets); | ||
1250 | if (!err) | ||
1251 | NLA_PUT(skb, DCB_ATTR_IEEE_ETS, sizeof(ets), &ets); | ||
1252 | } | ||
1253 | |||
1254 | if (ops->ieee_getpfc) { | ||
1255 | struct ieee_pfc pfc; | ||
1256 | err = ops->ieee_getpfc(netdev, &pfc); | ||
1257 | if (!err) | ||
1258 | NLA_PUT(skb, DCB_ATTR_IEEE_PFC, sizeof(pfc), &pfc); | ||
1259 | } | ||
1260 | |||
1261 | app = nla_nest_start(skb, DCB_ATTR_IEEE_APP_TABLE); | ||
1262 | if (!app) | ||
1263 | goto nla_put_failure; | ||
1264 | |||
1265 | spin_lock(&dcb_lock); | ||
1266 | list_for_each_entry(itr, &dcb_app_list, list) { | ||
1267 | if (strncmp(itr->name, netdev->name, IFNAMSIZ) == 0) | ||
1268 | NLA_PUT(skb, DCB_ATTR_IEEE_APP, | ||
1269 | sizeof(itr->app), &itr->app); | ||
1270 | } | ||
1271 | spin_unlock(&dcb_lock); | ||
1272 | nla_nest_end(skb, app); | ||
1273 | |||
1274 | nla_nest_end(skb, ieee); | ||
1275 | nlmsg_end(skb, nlh); | ||
1276 | |||
1277 | return rtnl_unicast(skb, &init_net, pid); | ||
1278 | nla_put_failure: | ||
1279 | nlmsg_cancel(skb, nlh); | ||
1280 | nlmsg_failure: | ||
1281 | kfree_skb(skb); | ||
1282 | return -1; | ||
1283 | } | ||
1284 | |||
1285 | /* DCBX configuration */ | ||
1286 | static int dcbnl_getdcbx(struct net_device *netdev, struct nlattr **tb, | ||
1287 | u32 pid, u32 seq, u16 flags) | ||
1288 | { | ||
1289 | int ret; | ||
1290 | |||
1291 | if (!netdev->dcbnl_ops->getdcbx) | ||
1292 | return -EOPNOTSUPP; | ||
1293 | |||
1294 | ret = dcbnl_reply(netdev->dcbnl_ops->getdcbx(netdev), RTM_GETDCB, | ||
1295 | DCB_CMD_GDCBX, DCB_ATTR_DCBX, pid, seq, flags); | ||
1296 | |||
1297 | return ret; | ||
1298 | } | ||
1299 | |||
1300 | static int dcbnl_setdcbx(struct net_device *netdev, struct nlattr **tb, | ||
1301 | u32 pid, u32 seq, u16 flags) | ||
1302 | { | ||
1303 | int ret; | ||
1304 | u8 value; | ||
1305 | |||
1306 | if (!netdev->dcbnl_ops->setdcbx) | ||
1307 | return -EOPNOTSUPP; | ||
1308 | |||
1309 | if (!tb[DCB_ATTR_DCBX]) | ||
1310 | return -EINVAL; | ||
1311 | |||
1312 | value = nla_get_u8(tb[DCB_ATTR_DCBX]); | ||
1313 | |||
1314 | ret = dcbnl_reply(netdev->dcbnl_ops->setdcbx(netdev, value), | ||
1315 | RTM_SETDCB, DCB_CMD_SDCBX, DCB_ATTR_DCBX, | ||
1316 | pid, seq, flags); | ||
1317 | |||
1318 | return ret; | ||
1319 | } | ||
1320 | |||
1321 | static int dcbnl_getfeatcfg(struct net_device *netdev, struct nlattr **tb, | ||
1322 | u32 pid, u32 seq, u16 flags) | ||
1323 | { | ||
1324 | struct sk_buff *dcbnl_skb; | ||
1325 | struct nlmsghdr *nlh; | ||
1326 | struct dcbmsg *dcb; | ||
1327 | struct nlattr *data[DCB_FEATCFG_ATTR_MAX + 1], *nest; | ||
1328 | u8 value; | ||
1329 | int ret, i; | ||
1330 | int getall = 0; | ||
1331 | |||
1332 | if (!netdev->dcbnl_ops->getfeatcfg) | ||
1333 | return -EOPNOTSUPP; | ||
1334 | |||
1335 | if (!tb[DCB_ATTR_FEATCFG]) | ||
1336 | return -EINVAL; | ||
1337 | |||
1338 | ret = nla_parse_nested(data, DCB_FEATCFG_ATTR_MAX, tb[DCB_ATTR_FEATCFG], | ||
1339 | dcbnl_featcfg_nest); | ||
1340 | if (ret) | ||
1341 | goto err_out; | ||
1342 | |||
1343 | dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
1344 | if (!dcbnl_skb) { | ||
1345 | ret = -ENOBUFS; | ||
1346 | goto err_out; | ||
1347 | } | ||
1348 | |||
1349 | nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); | ||
1350 | |||
1351 | dcb = NLMSG_DATA(nlh); | ||
1352 | dcb->dcb_family = AF_UNSPEC; | ||
1353 | dcb->cmd = DCB_CMD_GFEATCFG; | ||
1354 | |||
1355 | nest = nla_nest_start(dcbnl_skb, DCB_ATTR_FEATCFG); | ||
1356 | if (!nest) { | ||
1357 | ret = -EMSGSIZE; | ||
1358 | goto nla_put_failure; | ||
1359 | } | ||
1360 | |||
1361 | if (data[DCB_FEATCFG_ATTR_ALL]) | ||
1362 | getall = 1; | ||
1363 | |||
1364 | for (i = DCB_FEATCFG_ATTR_ALL+1; i <= DCB_FEATCFG_ATTR_MAX; i++) { | ||
1365 | if (!getall && !data[i]) | ||
1366 | continue; | ||
1367 | |||
1368 | ret = netdev->dcbnl_ops->getfeatcfg(netdev, i, &value); | ||
1369 | if (!ret) | ||
1370 | ret = nla_put_u8(dcbnl_skb, i, value); | ||
1371 | |||
1372 | if (ret) { | ||
1373 | nla_nest_cancel(dcbnl_skb, nest); | ||
1374 | goto nla_put_failure; | ||
1375 | } | ||
1376 | } | ||
1377 | nla_nest_end(dcbnl_skb, nest); | ||
1378 | |||
1379 | nlmsg_end(dcbnl_skb, nlh); | ||
1380 | |||
1381 | return rtnl_unicast(dcbnl_skb, &init_net, pid); | ||
1382 | nla_put_failure: | ||
1383 | nlmsg_cancel(dcbnl_skb, nlh); | ||
1384 | nlmsg_failure: | ||
1385 | kfree_skb(dcbnl_skb); | ||
1386 | err_out: | ||
1387 | return ret; | ||
1388 | } | ||
1389 | |||
1390 | static int dcbnl_setfeatcfg(struct net_device *netdev, struct nlattr **tb, | ||
1391 | u32 pid, u32 seq, u16 flags) | ||
1392 | { | ||
1393 | struct nlattr *data[DCB_FEATCFG_ATTR_MAX + 1]; | ||
1394 | int ret, i; | ||
1395 | u8 value; | ||
1396 | |||
1397 | if (!netdev->dcbnl_ops->setfeatcfg) | ||
1398 | return -ENOTSUPP; | ||
1399 | |||
1400 | if (!tb[DCB_ATTR_FEATCFG]) | ||
1401 | return -EINVAL; | ||
1402 | |||
1403 | ret = nla_parse_nested(data, DCB_FEATCFG_ATTR_MAX, tb[DCB_ATTR_FEATCFG], | ||
1404 | dcbnl_featcfg_nest); | ||
1405 | |||
1406 | if (ret) | ||
1407 | goto err; | ||
1408 | |||
1409 | for (i = DCB_FEATCFG_ATTR_ALL+1; i <= DCB_FEATCFG_ATTR_MAX; i++) { | ||
1410 | if (data[i] == NULL) | ||
1411 | continue; | ||
1412 | |||
1413 | value = nla_get_u8(data[i]); | ||
1414 | |||
1415 | ret = netdev->dcbnl_ops->setfeatcfg(netdev, i, value); | ||
1416 | |||
1417 | if (ret) | ||
1418 | goto err; | ||
1419 | } | ||
1420 | err: | ||
1421 | dcbnl_reply(ret, RTM_SETDCB, DCB_CMD_SFEATCFG, DCB_ATTR_FEATCFG, | ||
1422 | pid, seq, flags); | ||
1423 | |||
1424 | return ret; | ||
1425 | } | ||
1426 | |||
1121 | static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | 1427 | static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) |
1122 | { | 1428 | { |
1123 | struct net *net = sock_net(skb->sk); | 1429 | struct net *net = sock_net(skb->sk); |
@@ -1223,6 +1529,30 @@ static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
1223 | ret = dcbnl_setapp(netdev, tb, pid, nlh->nlmsg_seq, | 1529 | ret = dcbnl_setapp(netdev, tb, pid, nlh->nlmsg_seq, |
1224 | nlh->nlmsg_flags); | 1530 | nlh->nlmsg_flags); |
1225 | goto out; | 1531 | goto out; |
1532 | case DCB_CMD_IEEE_SET: | ||
1533 | ret = dcbnl_ieee_set(netdev, tb, pid, nlh->nlmsg_seq, | ||
1534 | nlh->nlmsg_flags); | ||
1535 | goto out; | ||
1536 | case DCB_CMD_IEEE_GET: | ||
1537 | ret = dcbnl_ieee_get(netdev, tb, pid, nlh->nlmsg_seq, | ||
1538 | nlh->nlmsg_flags); | ||
1539 | goto out; | ||
1540 | case DCB_CMD_GDCBX: | ||
1541 | ret = dcbnl_getdcbx(netdev, tb, pid, nlh->nlmsg_seq, | ||
1542 | nlh->nlmsg_flags); | ||
1543 | goto out; | ||
1544 | case DCB_CMD_SDCBX: | ||
1545 | ret = dcbnl_setdcbx(netdev, tb, pid, nlh->nlmsg_seq, | ||
1546 | nlh->nlmsg_flags); | ||
1547 | goto out; | ||
1548 | case DCB_CMD_GFEATCFG: | ||
1549 | ret = dcbnl_getfeatcfg(netdev, tb, pid, nlh->nlmsg_seq, | ||
1550 | nlh->nlmsg_flags); | ||
1551 | goto out; | ||
1552 | case DCB_CMD_SFEATCFG: | ||
1553 | ret = dcbnl_setfeatcfg(netdev, tb, pid, nlh->nlmsg_seq, | ||
1554 | nlh->nlmsg_flags); | ||
1555 | goto out; | ||
1226 | default: | 1556 | default: |
1227 | goto errout; | 1557 | goto errout; |
1228 | } | 1558 | } |
@@ -1233,8 +1563,94 @@ out: | |||
1233 | return ret; | 1563 | return ret; |
1234 | } | 1564 | } |
1235 | 1565 | ||
1566 | /** | ||
1567 | * dcb_getapp - retrieve the DCBX application user priority | ||
1568 | * | ||
1569 | * On success returns a non-zero 802.1p user priority bitmap | ||
1570 | * otherwise returns 0 as the invalid user priority bitmap to | ||
1571 | * indicate an error. | ||
1572 | */ | ||
1573 | u8 dcb_getapp(struct net_device *dev, struct dcb_app *app) | ||
1574 | { | ||
1575 | struct dcb_app_type *itr; | ||
1576 | u8 prio = 0; | ||
1577 | |||
1578 | spin_lock(&dcb_lock); | ||
1579 | list_for_each_entry(itr, &dcb_app_list, list) { | ||
1580 | if (itr->app.selector == app->selector && | ||
1581 | itr->app.protocol == app->protocol && | ||
1582 | (strncmp(itr->name, dev->name, IFNAMSIZ) == 0)) { | ||
1583 | prio = itr->app.priority; | ||
1584 | break; | ||
1585 | } | ||
1586 | } | ||
1587 | spin_unlock(&dcb_lock); | ||
1588 | |||
1589 | return prio; | ||
1590 | } | ||
1591 | EXPORT_SYMBOL(dcb_getapp); | ||
1592 | |||
1593 | /** | ||
1594 | * ixgbe_dcbnl_setapp - add dcb application data to app list | ||
1595 | * | ||
1596 | * Priority 0 is the default priority this removes applications | ||
1597 | * from the app list if the priority is set to zero. | ||
1598 | */ | ||
1599 | u8 dcb_setapp(struct net_device *dev, struct dcb_app *new) | ||
1600 | { | ||
1601 | struct dcb_app_type *itr; | ||
1602 | |||
1603 | spin_lock(&dcb_lock); | ||
1604 | /* Search for existing match and replace */ | ||
1605 | list_for_each_entry(itr, &dcb_app_list, list) { | ||
1606 | if (itr->app.selector == new->selector && | ||
1607 | itr->app.protocol == new->protocol && | ||
1608 | (strncmp(itr->name, dev->name, IFNAMSIZ) == 0)) { | ||
1609 | if (new->priority) | ||
1610 | itr->app.priority = new->priority; | ||
1611 | else { | ||
1612 | list_del(&itr->list); | ||
1613 | kfree(itr); | ||
1614 | } | ||
1615 | goto out; | ||
1616 | } | ||
1617 | } | ||
1618 | /* App type does not exist add new application type */ | ||
1619 | if (new->priority) { | ||
1620 | struct dcb_app_type *entry; | ||
1621 | entry = kmalloc(sizeof(struct dcb_app_type), GFP_ATOMIC); | ||
1622 | if (!entry) { | ||
1623 | spin_unlock(&dcb_lock); | ||
1624 | return -ENOMEM; | ||
1625 | } | ||
1626 | |||
1627 | memcpy(&entry->app, new, sizeof(*new)); | ||
1628 | strncpy(entry->name, dev->name, IFNAMSIZ); | ||
1629 | list_add(&entry->list, &dcb_app_list); | ||
1630 | } | ||
1631 | out: | ||
1632 | spin_unlock(&dcb_lock); | ||
1633 | call_dcbevent_notifiers(DCB_APP_EVENT, new); | ||
1634 | return 0; | ||
1635 | } | ||
1636 | EXPORT_SYMBOL(dcb_setapp); | ||
1637 | |||
1638 | static void dcb_flushapp(void) | ||
1639 | { | ||
1640 | struct dcb_app_type *app; | ||
1641 | |||
1642 | spin_lock(&dcb_lock); | ||
1643 | list_for_each_entry(app, &dcb_app_list, list) { | ||
1644 | list_del(&app->list); | ||
1645 | kfree(app); | ||
1646 | } | ||
1647 | spin_unlock(&dcb_lock); | ||
1648 | } | ||
1649 | |||
1236 | static int __init dcbnl_init(void) | 1650 | static int __init dcbnl_init(void) |
1237 | { | 1651 | { |
1652 | INIT_LIST_HEAD(&dcb_app_list); | ||
1653 | |||
1238 | rtnl_register(PF_UNSPEC, RTM_GETDCB, dcb_doit, NULL); | 1654 | rtnl_register(PF_UNSPEC, RTM_GETDCB, dcb_doit, NULL); |
1239 | rtnl_register(PF_UNSPEC, RTM_SETDCB, dcb_doit, NULL); | 1655 | rtnl_register(PF_UNSPEC, RTM_SETDCB, dcb_doit, NULL); |
1240 | 1656 | ||
@@ -1246,7 +1662,6 @@ static void __exit dcbnl_exit(void) | |||
1246 | { | 1662 | { |
1247 | rtnl_unregister(PF_UNSPEC, RTM_GETDCB); | 1663 | rtnl_unregister(PF_UNSPEC, RTM_GETDCB); |
1248 | rtnl_unregister(PF_UNSPEC, RTM_SETDCB); | 1664 | rtnl_unregister(PF_UNSPEC, RTM_SETDCB); |
1665 | dcb_flushapp(); | ||
1249 | } | 1666 | } |
1250 | module_exit(dcbnl_exit); | 1667 | module_exit(dcbnl_exit); |
1251 | |||
1252 | |||