aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Fastabend <john.r.fastabend@intel.com>2011-06-21 03:34:37 -0400
committerDavid S. Miller <davem@davemloft.net>2011-06-21 19:06:11 -0400
commit314b4778ed579f29b6d46ba90dbf31314c13805f (patch)
tree116b9424343f8261cacfa055e43455b588ce2893
parentc7797baf9f3900996ca800ab6298f95957bb4606 (diff)
net: dcbnl, add multicast group for DCB
Now that dcbnl is being used in many cases by more than a single agent it is beneficial to be notified when some entity either driver or user space has changed the DCB attributes. Today applications either end up polling the interface or relying on a user space database to maintain the DCB state and post events. Polling is a poor solution for obvious reasons. And relying on a user space database has its own downside. Namely it has created strange boot dependencies requiring the database be populated before any applications dependent on DCB attributes starts or the application goes into a polling loop. Populating the database requires negotiating link setting with the peer and can take anywhere from less than a second up to a few seconds depending on the switch implementation. Perhaps more importantly if another application or an embedded agent sets a DCB link attribute the database has no way of knowing other than polling the kernel. This prevents applications from responding quickly to changes in link events which at least in the FCoE case and probably any other protocols expecting a lossless link may result in IO errors. By adding a multicast group for DCB we have clean way to disseminate kernel DCB link attributes up to user space. Avoiding the need for user space to maintain a coherant database and disperse events that potentially do not reflect the current link state. Signed-off-by: John Fastabend <john.r.fastabend@intel.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/rtnetlink.h2
-rw-r--r--include/net/dcbnl.h2
-rw-r--r--net/dcb/dcbnl.c229
3 files changed, 150 insertions, 83 deletions
diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
index bbad657a3725..c81226a9a35c 100644
--- a/include/linux/rtnetlink.h
+++ b/include/linux/rtnetlink.h
@@ -585,6 +585,8 @@ enum rtnetlink_groups {
585#define RTNLGRP_PHONET_IFADDR RTNLGRP_PHONET_IFADDR 585#define RTNLGRP_PHONET_IFADDR RTNLGRP_PHONET_IFADDR
586 RTNLGRP_PHONET_ROUTE, 586 RTNLGRP_PHONET_ROUTE,
587#define RTNLGRP_PHONET_ROUTE RTNLGRP_PHONET_ROUTE 587#define RTNLGRP_PHONET_ROUTE RTNLGRP_PHONET_ROUTE
588 RTNLGRP_DCB,
589#define RTNLGRP_DCB RTNLGRP_DCB
588 __RTNLGRP_MAX 590 __RTNLGRP_MAX
589}; 591};
590#define RTNLGRP_MAX (__RTNLGRP_MAX - 1) 592#define RTNLGRP_MAX (__RTNLGRP_MAX - 1)
diff --git a/include/net/dcbnl.h b/include/net/dcbnl.h
index e5983c9053dc..b3cf10d9b828 100644
--- a/include/net/dcbnl.h
+++ b/include/net/dcbnl.h
@@ -31,6 +31,8 @@ struct dcb_app_type {
31u8 dcb_setapp(struct net_device *, struct dcb_app *); 31u8 dcb_setapp(struct net_device *, struct dcb_app *);
32u8 dcb_getapp(struct net_device *, struct dcb_app *); 32u8 dcb_getapp(struct net_device *, struct dcb_app *);
33 33
34int dcbnl_notify(struct net_device *dev, int event, int cmd, u32 seq, u32 pid);
35
34/* 36/*
35 * Ops struct for the netlink callbacks. Used by DCB-enabled drivers through 37 * Ops struct for the netlink callbacks. Used by DCB-enabled drivers through
36 * the netdevice struct. 38 * the netdevice struct.
diff --git a/net/dcb/dcbnl.c b/net/dcb/dcbnl.c
index 3a6d97d5280c..ffba32692bdb 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 */
1174static 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
1221err:
1222 dcbnl_reply(err, RTM_SETDCB, DCB_CMD_IEEE_SET, DCB_ATTR_IEEE,
1223 pid, seq, flags);
1224 return err;
1225}
1226
1227static int dcbnl_build_peer_app(struct net_device *netdev, struct sk_buff* skb, 1169static 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,30 +1221,13 @@ nla_put_failure:
1279} 1221}
1280 1222
1281/* Handle IEEE 802.1Qaz GET commands. */ 1223/* Handle IEEE 802.1Qaz GET commands. */
1282static int dcbnl_ieee_get(struct net_device *netdev, struct nlattr **tb, 1224static 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 dcbx; 1229 int dcbx;
1292 int err; 1230 int err = -EMSGSIZE;
1293
1294 if (!ops)
1295 return -EOPNOTSUPP;
1296
1297 skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1298 if (!skb)
1299 return -ENOBUFS;
1300
1301 nlh = NLMSG_NEW(skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
1302
1303 dcb = NLMSG_DATA(nlh);
1304 dcb->dcb_family = AF_UNSPEC;
1305 dcb->cmd = DCB_CMD_IEEE_GET;
1306 1231
1307 NLA_PUT_STRING(skb, DCB_ATTR_IFNAME, netdev->name); 1232 NLA_PUT_STRING(skb, DCB_ATTR_IFNAME, netdev->name);
1308 1233
@@ -1378,16 +1303,154 @@ static int dcbnl_ieee_get(struct net_device *netdev, struct nlattr **tb,
1378 if (err) 1303 if (err)
1379 goto nla_put_failure; 1304 goto nla_put_failure;
1380 } 1305 }
1381 nlmsg_end(skb, nlh);
1382 1306
1383 return rtnl_unicast(skb, &init_net, pid); 1307 return 0;
1308
1384nla_put_failure: 1309nla_put_failure:
1385 nlmsg_cancel(skb, nlh); 1310 return err;
1386nlmsg_failure:
1387 kfree_skb(skb);
1388 return -1;
1389} 1311}
1390 1312
1313int dcbnl_notify(struct net_device *dev, int event, int cmd,
1314 u32 seq, u32 pid)
1315{
1316 struct net *net = dev_net(dev);
1317 struct sk_buff *skb;
1318 struct nlmsghdr *nlh;
1319 struct dcbmsg *dcb;
1320 const struct dcbnl_rtnl_ops *ops = dev->dcbnl_ops;
1321 int err;
1322
1323 if (!ops)
1324 return -EOPNOTSUPP;
1325
1326 skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1327 if (!skb)
1328 return -ENOBUFS;
1329
1330 nlh = nlmsg_put(skb, pid, 0, event, sizeof(*dcb), 0);
1331 if (nlh == NULL) {
1332 kfree(skb);
1333 return -EMSGSIZE;
1334 }
1335
1336 dcb = NLMSG_DATA(nlh);
1337 dcb->dcb_family = AF_UNSPEC;
1338 dcb->cmd = cmd;
1339
1340 err = dcbnl_ieee_fill(skb, dev);
1341 if (err < 0) {
1342 /* Report error to broadcast listeners */
1343 nlmsg_cancel(skb, nlh);
1344 kfree_skb(skb);
1345 rtnl_set_sk_err(net, RTNLGRP_DCB, err);
1346 } else {
1347 /* End nlmsg and notify broadcast listeners */
1348 nlmsg_end(skb, nlh);
1349 rtnl_notify(skb, net, 0, RTNLGRP_DCB, NULL, GFP_KERNEL);
1350 }
1351
1352 return err;
1353}
1354EXPORT_SYMBOL(dcbnl_notify);
1355
1356/* Handle IEEE 802.1Qaz SET commands. If any requested operation can not
1357 * be completed the entire msg is aborted and error value is returned.
1358 * No attempt is made to reconcile the case where only part of the
1359 * cmd can be completed.
1360 */
1361static int dcbnl_ieee_set(struct net_device *netdev, struct nlattr **tb,
1362 u32 pid, u32 seq, u16 flags)
1363{
1364 const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
1365 struct nlattr *ieee[DCB_ATTR_IEEE_MAX + 1];
1366 int err = -EOPNOTSUPP;
1367
1368 if (!ops)
1369 return err;
1370
1371 err = nla_parse_nested(ieee, DCB_ATTR_IEEE_MAX,
1372 tb[DCB_ATTR_IEEE], dcbnl_ieee_policy);
1373 if (err)
1374 return err;
1375
1376 if (ieee[DCB_ATTR_IEEE_ETS] && ops->ieee_setets) {
1377 struct ieee_ets *ets = nla_data(ieee[DCB_ATTR_IEEE_ETS]);
1378 err = ops->ieee_setets(netdev, ets);
1379 if (err)
1380 goto err;
1381 }
1382
1383 if (ieee[DCB_ATTR_IEEE_PFC] && ops->ieee_setpfc) {
1384 struct ieee_pfc *pfc = nla_data(ieee[DCB_ATTR_IEEE_PFC]);
1385 err = ops->ieee_setpfc(netdev, pfc);
1386 if (err)
1387 goto err;
1388 }
1389
1390 if (ieee[DCB_ATTR_IEEE_APP_TABLE]) {
1391 struct nlattr *attr;
1392 int rem;
1393
1394 nla_for_each_nested(attr, ieee[DCB_ATTR_IEEE_APP_TABLE], rem) {
1395 struct dcb_app *app_data;
1396 if (nla_type(attr) != DCB_ATTR_IEEE_APP)
1397 continue;
1398 app_data = nla_data(attr);
1399 if (ops->ieee_setapp)
1400 err = ops->ieee_setapp(netdev, app_data);
1401 else
1402 err = dcb_setapp(netdev, app_data);
1403 if (err)
1404 goto err;
1405 }
1406 }
1407
1408err:
1409 dcbnl_reply(err, RTM_SETDCB, DCB_CMD_IEEE_SET, DCB_ATTR_IEEE,
1410 pid, seq, flags);
1411 dcbnl_notify(netdev, RTM_SETDCB, DCB_CMD_IEEE_SET, seq, 0);
1412 return err;
1413}
1414
1415static int dcbnl_ieee_get(struct net_device *netdev, struct nlattr **tb,
1416 u32 pid, u32 seq, u16 flags)
1417{
1418 struct net *net = dev_net(netdev);
1419 struct sk_buff *skb;
1420 struct nlmsghdr *nlh;
1421 struct dcbmsg *dcb;
1422 const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
1423 int err;
1424
1425 if (!ops)
1426 return -EOPNOTSUPP;
1427
1428 skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1429 if (!skb)
1430 return -ENOBUFS;
1431
1432 nlh = nlmsg_put(skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
1433 if (nlh == NULL) {
1434 kfree(skb);
1435 return -EMSGSIZE;
1436 }
1437
1438 dcb = NLMSG_DATA(nlh);
1439 dcb->dcb_family = AF_UNSPEC;
1440 dcb->cmd = DCB_CMD_IEEE_GET;
1441
1442 err = dcbnl_ieee_fill(skb, netdev);
1443
1444 if (err < 0) {
1445 nlmsg_cancel(skb, nlh);
1446 kfree_skb(skb);
1447 } else {
1448 nlmsg_end(skb, nlh);
1449 err = rtnl_unicast(skb, net, pid);
1450 }
1451
1452 return err;
1453}
1391/* DCBX configuration */ 1454/* DCBX configuration */
1392static int dcbnl_getdcbx(struct net_device *netdev, struct nlattr **tb, 1455static int dcbnl_getdcbx(struct net_device *netdev, struct nlattr **tb,
1393 u32 pid, u32 seq, u16 flags) 1456 u32 pid, u32 seq, u16 flags)