diff options
Diffstat (limited to 'net/dcb/dcbnl.c')
-rw-r--r-- | net/dcb/dcbnl.c | 455 |
1 files changed, 446 insertions, 9 deletions
diff --git a/net/dcb/dcbnl.c b/net/dcb/dcbnl.c index 19ac2b985485..d5074a567289 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) |
@@ -556,7 +583,7 @@ static int dcbnl_getapp(struct net_device *netdev, struct nlattr **tb, | |||
556 | u8 up, idtype; | 583 | u8 up, idtype; |
557 | int ret = -EINVAL; | 584 | int ret = -EINVAL; |
558 | 585 | ||
559 | if (!tb[DCB_ATTR_APP] || !netdev->dcbnl_ops->getapp) | 586 | if (!tb[DCB_ATTR_APP]) |
560 | goto out; | 587 | goto out; |
561 | 588 | ||
562 | ret = nla_parse_nested(app_tb, DCB_APP_ATTR_MAX, tb[DCB_ATTR_APP], | 589 | ret = nla_parse_nested(app_tb, DCB_APP_ATTR_MAX, tb[DCB_ATTR_APP], |
@@ -577,7 +604,16 @@ static int dcbnl_getapp(struct net_device *netdev, struct nlattr **tb, | |||
577 | goto out; | 604 | goto out; |
578 | 605 | ||
579 | id = nla_get_u16(app_tb[DCB_APP_ATTR_ID]); | 606 | id = nla_get_u16(app_tb[DCB_APP_ATTR_ID]); |
580 | up = netdev->dcbnl_ops->getapp(netdev, idtype, id); | 607 | |
608 | if (netdev->dcbnl_ops->getapp) { | ||
609 | up = netdev->dcbnl_ops->getapp(netdev, idtype, id); | ||
610 | } else { | ||
611 | struct dcb_app app = { | ||
612 | .selector = idtype, | ||
613 | .protocol = id, | ||
614 | }; | ||
615 | up = dcb_getapp(netdev, &app); | ||
616 | } | ||
581 | 617 | ||
582 | /* send this back */ | 618 | /* send this back */ |
583 | dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 619 | dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
@@ -590,6 +626,9 @@ static int dcbnl_getapp(struct net_device *netdev, struct nlattr **tb, | |||
590 | dcb->cmd = DCB_CMD_GAPP; | 626 | dcb->cmd = DCB_CMD_GAPP; |
591 | 627 | ||
592 | app_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_APP); | 628 | app_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_APP); |
629 | if (!app_nest) | ||
630 | goto out_cancel; | ||
631 | |||
593 | ret = nla_put_u8(dcbnl_skb, DCB_APP_ATTR_IDTYPE, idtype); | 632 | ret = nla_put_u8(dcbnl_skb, DCB_APP_ATTR_IDTYPE, idtype); |
594 | if (ret) | 633 | if (ret) |
595 | goto out_cancel; | 634 | goto out_cancel; |
@@ -622,12 +661,12 @@ out: | |||
622 | static int dcbnl_setapp(struct net_device *netdev, struct nlattr **tb, | 661 | static int dcbnl_setapp(struct net_device *netdev, struct nlattr **tb, |
623 | u32 pid, u32 seq, u16 flags) | 662 | u32 pid, u32 seq, u16 flags) |
624 | { | 663 | { |
625 | int ret = -EINVAL; | 664 | int err, ret = -EINVAL; |
626 | u16 id; | 665 | u16 id; |
627 | u8 up, idtype; | 666 | u8 up, idtype; |
628 | struct nlattr *app_tb[DCB_APP_ATTR_MAX + 1]; | 667 | struct nlattr *app_tb[DCB_APP_ATTR_MAX + 1]; |
629 | 668 | ||
630 | if (!tb[DCB_ATTR_APP] || !netdev->dcbnl_ops->setapp) | 669 | if (!tb[DCB_ATTR_APP]) |
631 | goto out; | 670 | goto out; |
632 | 671 | ||
633 | ret = nla_parse_nested(app_tb, DCB_APP_ATTR_MAX, tb[DCB_ATTR_APP], | 672 | ret = nla_parse_nested(app_tb, DCB_APP_ATTR_MAX, tb[DCB_ATTR_APP], |
@@ -651,9 +690,18 @@ static int dcbnl_setapp(struct net_device *netdev, struct nlattr **tb, | |||
651 | id = nla_get_u16(app_tb[DCB_APP_ATTR_ID]); | 690 | id = nla_get_u16(app_tb[DCB_APP_ATTR_ID]); |
652 | up = nla_get_u8(app_tb[DCB_APP_ATTR_PRIORITY]); | 691 | up = nla_get_u8(app_tb[DCB_APP_ATTR_PRIORITY]); |
653 | 692 | ||
654 | ret = dcbnl_reply(netdev->dcbnl_ops->setapp(netdev, idtype, id, up), | 693 | if (netdev->dcbnl_ops->setapp) { |
655 | RTM_SETDCB, DCB_CMD_SAPP, DCB_ATTR_APP, | 694 | err = netdev->dcbnl_ops->setapp(netdev, idtype, id, up); |
656 | pid, seq, flags); | 695 | } else { |
696 | struct dcb_app app; | ||
697 | app.selector = idtype; | ||
698 | app.protocol = id; | ||
699 | app.priority = up; | ||
700 | err = dcb_setapp(netdev, &app); | ||
701 | } | ||
702 | |||
703 | ret = dcbnl_reply(err, RTM_SETDCB, DCB_CMD_SAPP, DCB_ATTR_APP, | ||
704 | pid, seq, flags); | ||
657 | out: | 705 | out: |
658 | return ret; | 706 | return ret; |
659 | } | 707 | } |
@@ -1118,6 +1166,281 @@ err: | |||
1118 | return ret; | 1166 | return ret; |
1119 | } | 1167 | } |
1120 | 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_setets) { | ||
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 | |||
1228 | /* Handle IEEE 802.1Qaz GET commands. */ | ||
1229 | static int dcbnl_ieee_get(struct net_device *netdev, struct nlattr **tb, | ||
1230 | u32 pid, u32 seq, u16 flags) | ||
1231 | { | ||
1232 | struct sk_buff *skb; | ||
1233 | struct nlmsghdr *nlh; | ||
1234 | struct dcbmsg *dcb; | ||
1235 | struct nlattr *ieee, *app; | ||
1236 | struct dcb_app_type *itr; | ||
1237 | const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; | ||
1238 | int err; | ||
1239 | |||
1240 | if (!ops) | ||
1241 | return -EOPNOTSUPP; | ||
1242 | |||
1243 | skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
1244 | if (!skb) | ||
1245 | return -ENOBUFS; | ||
1246 | |||
1247 | nlh = NLMSG_NEW(skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); | ||
1248 | |||
1249 | dcb = NLMSG_DATA(nlh); | ||
1250 | dcb->dcb_family = AF_UNSPEC; | ||
1251 | dcb->cmd = DCB_CMD_IEEE_GET; | ||
1252 | |||
1253 | NLA_PUT_STRING(skb, DCB_ATTR_IFNAME, netdev->name); | ||
1254 | |||
1255 | ieee = nla_nest_start(skb, DCB_ATTR_IEEE); | ||
1256 | if (!ieee) | ||
1257 | goto nla_put_failure; | ||
1258 | |||
1259 | if (ops->ieee_getets) { | ||
1260 | struct ieee_ets ets; | ||
1261 | err = ops->ieee_getets(netdev, &ets); | ||
1262 | if (!err) | ||
1263 | NLA_PUT(skb, DCB_ATTR_IEEE_ETS, sizeof(ets), &ets); | ||
1264 | } | ||
1265 | |||
1266 | if (ops->ieee_getpfc) { | ||
1267 | struct ieee_pfc pfc; | ||
1268 | err = ops->ieee_getpfc(netdev, &pfc); | ||
1269 | if (!err) | ||
1270 | NLA_PUT(skb, DCB_ATTR_IEEE_PFC, sizeof(pfc), &pfc); | ||
1271 | } | ||
1272 | |||
1273 | app = nla_nest_start(skb, DCB_ATTR_IEEE_APP_TABLE); | ||
1274 | if (!app) | ||
1275 | goto nla_put_failure; | ||
1276 | |||
1277 | spin_lock(&dcb_lock); | ||
1278 | list_for_each_entry(itr, &dcb_app_list, list) { | ||
1279 | if (strncmp(itr->name, netdev->name, IFNAMSIZ) == 0) { | ||
1280 | err = nla_put(skb, DCB_ATTR_IEEE_APP, sizeof(itr->app), | ||
1281 | &itr->app); | ||
1282 | if (err) { | ||
1283 | spin_unlock(&dcb_lock); | ||
1284 | goto nla_put_failure; | ||
1285 | } | ||
1286 | } | ||
1287 | } | ||
1288 | spin_unlock(&dcb_lock); | ||
1289 | nla_nest_end(skb, app); | ||
1290 | |||
1291 | nla_nest_end(skb, ieee); | ||
1292 | nlmsg_end(skb, nlh); | ||
1293 | |||
1294 | return rtnl_unicast(skb, &init_net, pid); | ||
1295 | nla_put_failure: | ||
1296 | nlmsg_cancel(skb, nlh); | ||
1297 | nlmsg_failure: | ||
1298 | kfree_skb(skb); | ||
1299 | return -1; | ||
1300 | } | ||
1301 | |||
1302 | /* DCBX configuration */ | ||
1303 | static int dcbnl_getdcbx(struct net_device *netdev, struct nlattr **tb, | ||
1304 | u32 pid, u32 seq, u16 flags) | ||
1305 | { | ||
1306 | int ret; | ||
1307 | |||
1308 | if (!netdev->dcbnl_ops->getdcbx) | ||
1309 | return -EOPNOTSUPP; | ||
1310 | |||
1311 | ret = dcbnl_reply(netdev->dcbnl_ops->getdcbx(netdev), RTM_GETDCB, | ||
1312 | DCB_CMD_GDCBX, DCB_ATTR_DCBX, pid, seq, flags); | ||
1313 | |||
1314 | return ret; | ||
1315 | } | ||
1316 | |||
1317 | static int dcbnl_setdcbx(struct net_device *netdev, struct nlattr **tb, | ||
1318 | u32 pid, u32 seq, u16 flags) | ||
1319 | { | ||
1320 | int ret; | ||
1321 | u8 value; | ||
1322 | |||
1323 | if (!netdev->dcbnl_ops->setdcbx) | ||
1324 | return -EOPNOTSUPP; | ||
1325 | |||
1326 | if (!tb[DCB_ATTR_DCBX]) | ||
1327 | return -EINVAL; | ||
1328 | |||
1329 | value = nla_get_u8(tb[DCB_ATTR_DCBX]); | ||
1330 | |||
1331 | ret = dcbnl_reply(netdev->dcbnl_ops->setdcbx(netdev, value), | ||
1332 | RTM_SETDCB, DCB_CMD_SDCBX, DCB_ATTR_DCBX, | ||
1333 | pid, seq, flags); | ||
1334 | |||
1335 | return ret; | ||
1336 | } | ||
1337 | |||
1338 | static int dcbnl_getfeatcfg(struct net_device *netdev, struct nlattr **tb, | ||
1339 | u32 pid, u32 seq, u16 flags) | ||
1340 | { | ||
1341 | struct sk_buff *dcbnl_skb; | ||
1342 | struct nlmsghdr *nlh; | ||
1343 | struct dcbmsg *dcb; | ||
1344 | struct nlattr *data[DCB_FEATCFG_ATTR_MAX + 1], *nest; | ||
1345 | u8 value; | ||
1346 | int ret, i; | ||
1347 | int getall = 0; | ||
1348 | |||
1349 | if (!netdev->dcbnl_ops->getfeatcfg) | ||
1350 | return -EOPNOTSUPP; | ||
1351 | |||
1352 | if (!tb[DCB_ATTR_FEATCFG]) | ||
1353 | return -EINVAL; | ||
1354 | |||
1355 | ret = nla_parse_nested(data, DCB_FEATCFG_ATTR_MAX, tb[DCB_ATTR_FEATCFG], | ||
1356 | dcbnl_featcfg_nest); | ||
1357 | if (ret) | ||
1358 | goto err_out; | ||
1359 | |||
1360 | dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
1361 | if (!dcbnl_skb) { | ||
1362 | ret = -ENOBUFS; | ||
1363 | goto err_out; | ||
1364 | } | ||
1365 | |||
1366 | nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); | ||
1367 | |||
1368 | dcb = NLMSG_DATA(nlh); | ||
1369 | dcb->dcb_family = AF_UNSPEC; | ||
1370 | dcb->cmd = DCB_CMD_GFEATCFG; | ||
1371 | |||
1372 | nest = nla_nest_start(dcbnl_skb, DCB_ATTR_FEATCFG); | ||
1373 | if (!nest) { | ||
1374 | ret = -EMSGSIZE; | ||
1375 | goto nla_put_failure; | ||
1376 | } | ||
1377 | |||
1378 | if (data[DCB_FEATCFG_ATTR_ALL]) | ||
1379 | getall = 1; | ||
1380 | |||
1381 | for (i = DCB_FEATCFG_ATTR_ALL+1; i <= DCB_FEATCFG_ATTR_MAX; i++) { | ||
1382 | if (!getall && !data[i]) | ||
1383 | continue; | ||
1384 | |||
1385 | ret = netdev->dcbnl_ops->getfeatcfg(netdev, i, &value); | ||
1386 | if (!ret) | ||
1387 | ret = nla_put_u8(dcbnl_skb, i, value); | ||
1388 | |||
1389 | if (ret) { | ||
1390 | nla_nest_cancel(dcbnl_skb, nest); | ||
1391 | goto nla_put_failure; | ||
1392 | } | ||
1393 | } | ||
1394 | nla_nest_end(dcbnl_skb, nest); | ||
1395 | |||
1396 | nlmsg_end(dcbnl_skb, nlh); | ||
1397 | |||
1398 | return rtnl_unicast(dcbnl_skb, &init_net, pid); | ||
1399 | nla_put_failure: | ||
1400 | nlmsg_cancel(dcbnl_skb, nlh); | ||
1401 | nlmsg_failure: | ||
1402 | kfree_skb(dcbnl_skb); | ||
1403 | err_out: | ||
1404 | return ret; | ||
1405 | } | ||
1406 | |||
1407 | static int dcbnl_setfeatcfg(struct net_device *netdev, struct nlattr **tb, | ||
1408 | u32 pid, u32 seq, u16 flags) | ||
1409 | { | ||
1410 | struct nlattr *data[DCB_FEATCFG_ATTR_MAX + 1]; | ||
1411 | int ret, i; | ||
1412 | u8 value; | ||
1413 | |||
1414 | if (!netdev->dcbnl_ops->setfeatcfg) | ||
1415 | return -ENOTSUPP; | ||
1416 | |||
1417 | if (!tb[DCB_ATTR_FEATCFG]) | ||
1418 | return -EINVAL; | ||
1419 | |||
1420 | ret = nla_parse_nested(data, DCB_FEATCFG_ATTR_MAX, tb[DCB_ATTR_FEATCFG], | ||
1421 | dcbnl_featcfg_nest); | ||
1422 | |||
1423 | if (ret) | ||
1424 | goto err; | ||
1425 | |||
1426 | for (i = DCB_FEATCFG_ATTR_ALL+1; i <= DCB_FEATCFG_ATTR_MAX; i++) { | ||
1427 | if (data[i] == NULL) | ||
1428 | continue; | ||
1429 | |||
1430 | value = nla_get_u8(data[i]); | ||
1431 | |||
1432 | ret = netdev->dcbnl_ops->setfeatcfg(netdev, i, value); | ||
1433 | |||
1434 | if (ret) | ||
1435 | goto err; | ||
1436 | } | ||
1437 | err: | ||
1438 | dcbnl_reply(ret, RTM_SETDCB, DCB_CMD_SFEATCFG, DCB_ATTR_FEATCFG, | ||
1439 | pid, seq, flags); | ||
1440 | |||
1441 | return ret; | ||
1442 | } | ||
1443 | |||
1121 | static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | 1444 | static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) |
1122 | { | 1445 | { |
1123 | struct net *net = sock_net(skb->sk); | 1446 | struct net *net = sock_net(skb->sk); |
@@ -1223,6 +1546,30 @@ static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
1223 | ret = dcbnl_setapp(netdev, tb, pid, nlh->nlmsg_seq, | 1546 | ret = dcbnl_setapp(netdev, tb, pid, nlh->nlmsg_seq, |
1224 | nlh->nlmsg_flags); | 1547 | nlh->nlmsg_flags); |
1225 | goto out; | 1548 | goto out; |
1549 | case DCB_CMD_IEEE_SET: | ||
1550 | ret = dcbnl_ieee_set(netdev, tb, pid, nlh->nlmsg_seq, | ||
1551 | nlh->nlmsg_flags); | ||
1552 | goto out; | ||
1553 | case DCB_CMD_IEEE_GET: | ||
1554 | ret = dcbnl_ieee_get(netdev, tb, pid, nlh->nlmsg_seq, | ||
1555 | nlh->nlmsg_flags); | ||
1556 | goto out; | ||
1557 | case DCB_CMD_GDCBX: | ||
1558 | ret = dcbnl_getdcbx(netdev, tb, pid, nlh->nlmsg_seq, | ||
1559 | nlh->nlmsg_flags); | ||
1560 | goto out; | ||
1561 | case DCB_CMD_SDCBX: | ||
1562 | ret = dcbnl_setdcbx(netdev, tb, pid, nlh->nlmsg_seq, | ||
1563 | nlh->nlmsg_flags); | ||
1564 | goto out; | ||
1565 | case DCB_CMD_GFEATCFG: | ||
1566 | ret = dcbnl_getfeatcfg(netdev, tb, pid, nlh->nlmsg_seq, | ||
1567 | nlh->nlmsg_flags); | ||
1568 | goto out; | ||
1569 | case DCB_CMD_SFEATCFG: | ||
1570 | ret = dcbnl_setfeatcfg(netdev, tb, pid, nlh->nlmsg_seq, | ||
1571 | nlh->nlmsg_flags); | ||
1572 | goto out; | ||
1226 | default: | 1573 | default: |
1227 | goto errout; | 1574 | goto errout; |
1228 | } | 1575 | } |
@@ -1233,8 +1580,99 @@ out: | |||
1233 | return ret; | 1580 | return ret; |
1234 | } | 1581 | } |
1235 | 1582 | ||
1583 | /** | ||
1584 | * dcb_getapp - retrieve the DCBX application user priority | ||
1585 | * | ||
1586 | * On success returns a non-zero 802.1p user priority bitmap | ||
1587 | * otherwise returns 0 as the invalid user priority bitmap to | ||
1588 | * indicate an error. | ||
1589 | */ | ||
1590 | u8 dcb_getapp(struct net_device *dev, struct dcb_app *app) | ||
1591 | { | ||
1592 | struct dcb_app_type *itr; | ||
1593 | u8 prio = 0; | ||
1594 | |||
1595 | spin_lock(&dcb_lock); | ||
1596 | list_for_each_entry(itr, &dcb_app_list, list) { | ||
1597 | if (itr->app.selector == app->selector && | ||
1598 | itr->app.protocol == app->protocol && | ||
1599 | (strncmp(itr->name, dev->name, IFNAMSIZ) == 0)) { | ||
1600 | prio = itr->app.priority; | ||
1601 | break; | ||
1602 | } | ||
1603 | } | ||
1604 | spin_unlock(&dcb_lock); | ||
1605 | |||
1606 | return prio; | ||
1607 | } | ||
1608 | EXPORT_SYMBOL(dcb_getapp); | ||
1609 | |||
1610 | /** | ||
1611 | * ixgbe_dcbnl_setapp - add dcb application data to app list | ||
1612 | * | ||
1613 | * Priority 0 is the default priority this removes applications | ||
1614 | * from the app list if the priority is set to zero. | ||
1615 | */ | ||
1616 | u8 dcb_setapp(struct net_device *dev, struct dcb_app *new) | ||
1617 | { | ||
1618 | struct dcb_app_type *itr; | ||
1619 | struct dcb_app_type event; | ||
1620 | |||
1621 | memcpy(&event.name, dev->name, sizeof(event.name)); | ||
1622 | memcpy(&event.app, new, sizeof(event.app)); | ||
1623 | |||
1624 | spin_lock(&dcb_lock); | ||
1625 | /* Search for existing match and replace */ | ||
1626 | list_for_each_entry(itr, &dcb_app_list, list) { | ||
1627 | if (itr->app.selector == new->selector && | ||
1628 | itr->app.protocol == new->protocol && | ||
1629 | (strncmp(itr->name, dev->name, IFNAMSIZ) == 0)) { | ||
1630 | if (new->priority) | ||
1631 | itr->app.priority = new->priority; | ||
1632 | else { | ||
1633 | list_del(&itr->list); | ||
1634 | kfree(itr); | ||
1635 | } | ||
1636 | goto out; | ||
1637 | } | ||
1638 | } | ||
1639 | /* App type does not exist add new application type */ | ||
1640 | if (new->priority) { | ||
1641 | struct dcb_app_type *entry; | ||
1642 | entry = kmalloc(sizeof(struct dcb_app_type), GFP_ATOMIC); | ||
1643 | if (!entry) { | ||
1644 | spin_unlock(&dcb_lock); | ||
1645 | return -ENOMEM; | ||
1646 | } | ||
1647 | |||
1648 | memcpy(&entry->app, new, sizeof(*new)); | ||
1649 | strncpy(entry->name, dev->name, IFNAMSIZ); | ||
1650 | list_add(&entry->list, &dcb_app_list); | ||
1651 | } | ||
1652 | out: | ||
1653 | spin_unlock(&dcb_lock); | ||
1654 | call_dcbevent_notifiers(DCB_APP_EVENT, &event); | ||
1655 | return 0; | ||
1656 | } | ||
1657 | EXPORT_SYMBOL(dcb_setapp); | ||
1658 | |||
1659 | static void dcb_flushapp(void) | ||
1660 | { | ||
1661 | struct dcb_app_type *app; | ||
1662 | struct dcb_app_type *tmp; | ||
1663 | |||
1664 | spin_lock(&dcb_lock); | ||
1665 | list_for_each_entry_safe(app, tmp, &dcb_app_list, list) { | ||
1666 | list_del(&app->list); | ||
1667 | kfree(app); | ||
1668 | } | ||
1669 | spin_unlock(&dcb_lock); | ||
1670 | } | ||
1671 | |||
1236 | static int __init dcbnl_init(void) | 1672 | static int __init dcbnl_init(void) |
1237 | { | 1673 | { |
1674 | INIT_LIST_HEAD(&dcb_app_list); | ||
1675 | |||
1238 | rtnl_register(PF_UNSPEC, RTM_GETDCB, dcb_doit, NULL); | 1676 | rtnl_register(PF_UNSPEC, RTM_GETDCB, dcb_doit, NULL); |
1239 | rtnl_register(PF_UNSPEC, RTM_SETDCB, dcb_doit, NULL); | 1677 | rtnl_register(PF_UNSPEC, RTM_SETDCB, dcb_doit, NULL); |
1240 | 1678 | ||
@@ -1246,7 +1684,6 @@ static void __exit dcbnl_exit(void) | |||
1246 | { | 1684 | { |
1247 | rtnl_unregister(PF_UNSPEC, RTM_GETDCB); | 1685 | rtnl_unregister(PF_UNSPEC, RTM_GETDCB); |
1248 | rtnl_unregister(PF_UNSPEC, RTM_SETDCB); | 1686 | rtnl_unregister(PF_UNSPEC, RTM_SETDCB); |
1687 | dcb_flushapp(); | ||
1249 | } | 1688 | } |
1250 | module_exit(dcbnl_exit); | 1689 | module_exit(dcbnl_exit); |
1251 | |||
1252 | |||