aboutsummaryrefslogtreecommitdiffstats
path: root/net/openvswitch/datapath.c
diff options
context:
space:
mode:
authorJarno Rajahalme <jrajahalme@nicira.com>2014-05-05 17:13:32 -0400
committerPravin B Shelar <pshelar@nicira.com>2014-05-22 19:27:35 -0400
commit6093ae9abac18871afd0bbc5cf093dff53112fcb (patch)
tree23ea64a6a9987a2e1b45e7fbe5689c7767cb3f5b /net/openvswitch/datapath.c
parent56c19868e115fcf8d62d843e1b9616bb9837d0db (diff)
openvswitch: Minimize dp and vport critical sections.
Move most memory allocations away from the ovs_mutex critical sections. vport allocations still happen while the lock is taken, as changing that would require major refactoring. Also, vports are created very rarely so it should not matter. Change ovs_dp_cmd_get() now only takes the rcu_read_lock(), rather than ovs_lock(), as nothing need to be changed. This was done by ovs_vport_cmd_get() already. Signed-off-by: Jarno Rajahalme <jrajahalme@nicira.com> Signed-off-by: Pravin B Shelar <pshelar@nicira.com>
Diffstat (limited to 'net/openvswitch/datapath.c')
-rw-r--r--net/openvswitch/datapath.c218
1 files changed, 110 insertions, 108 deletions
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c
index cb5d64a5c759..f3bcdac80bda 100644
--- a/net/openvswitch/datapath.c
+++ b/net/openvswitch/datapath.c
@@ -1164,23 +1164,9 @@ error:
1164 return -EMSGSIZE; 1164 return -EMSGSIZE;
1165} 1165}
1166 1166
1167/* Must be called with ovs_mutex. */ 1167static struct sk_buff *ovs_dp_cmd_alloc_info(struct genl_info *info)
1168static struct sk_buff *ovs_dp_cmd_build_info(struct datapath *dp,
1169 struct genl_info *info, u8 cmd)
1170{ 1168{
1171 struct sk_buff *skb; 1169 return genlmsg_new_unicast(ovs_dp_cmd_msg_size(), info, GFP_KERNEL);
1172 int retval;
1173
1174 skb = genlmsg_new_unicast(ovs_dp_cmd_msg_size(), info, GFP_KERNEL);
1175 if (!skb)
1176 return ERR_PTR(-ENOMEM);
1177
1178 retval = ovs_dp_cmd_fill_info(dp, skb, info->snd_portid, info->snd_seq, 0, cmd);
1179 if (retval < 0) {
1180 kfree_skb(skb);
1181 return ERR_PTR(retval);
1182 }
1183 return skb;
1184} 1170}
1185 1171
1186/* Called with rcu_read_lock or ovs_mutex. */ 1172/* Called with rcu_read_lock or ovs_mutex. */
@@ -1233,12 +1219,14 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
1233 if (!a[OVS_DP_ATTR_NAME] || !a[OVS_DP_ATTR_UPCALL_PID]) 1219 if (!a[OVS_DP_ATTR_NAME] || !a[OVS_DP_ATTR_UPCALL_PID])
1234 goto err; 1220 goto err;
1235 1221
1236 ovs_lock(); 1222 reply = ovs_dp_cmd_alloc_info(info);
1223 if (!reply)
1224 return -ENOMEM;
1237 1225
1238 err = -ENOMEM; 1226 err = -ENOMEM;
1239 dp = kzalloc(sizeof(*dp), GFP_KERNEL); 1227 dp = kzalloc(sizeof(*dp), GFP_KERNEL);
1240 if (dp == NULL) 1228 if (dp == NULL)
1241 goto err_unlock_ovs; 1229 goto err_free_reply;
1242 1230
1243 ovs_dp_set_net(dp, hold_net(sock_net(skb->sk))); 1231 ovs_dp_set_net(dp, hold_net(sock_net(skb->sk)));
1244 1232
@@ -1273,6 +1261,9 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
1273 1261
1274 ovs_dp_change(dp, a); 1262 ovs_dp_change(dp, a);
1275 1263
1264 /* So far only local changes have been made, now need the lock. */
1265 ovs_lock();
1266
1276 vport = new_vport(&parms); 1267 vport = new_vport(&parms);
1277 if (IS_ERR(vport)) { 1268 if (IS_ERR(vport)) {
1278 err = PTR_ERR(vport); 1269 err = PTR_ERR(vport);
@@ -1291,10 +1282,9 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
1291 goto err_destroy_ports_array; 1282 goto err_destroy_ports_array;
1292 } 1283 }
1293 1284
1294 reply = ovs_dp_cmd_build_info(dp, info, OVS_DP_CMD_NEW); 1285 err = ovs_dp_cmd_fill_info(dp, reply, info->snd_portid,
1295 err = PTR_ERR(reply); 1286 info->snd_seq, 0, OVS_DP_CMD_NEW);
1296 if (IS_ERR(reply)) 1287 BUG_ON(err < 0);
1297 goto err_destroy_local_port;
1298 1288
1299 ovs_net = net_generic(ovs_dp_get_net(dp), ovs_net_id); 1289 ovs_net = net_generic(ovs_dp_get_net(dp), ovs_net_id);
1300 list_add_tail_rcu(&dp->list_node, &ovs_net->dps); 1290 list_add_tail_rcu(&dp->list_node, &ovs_net->dps);
@@ -1304,9 +1294,8 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
1304 ovs_notify(&dp_datapath_genl_family, reply, info); 1294 ovs_notify(&dp_datapath_genl_family, reply, info);
1305 return 0; 1295 return 0;
1306 1296
1307err_destroy_local_port:
1308 ovs_dp_detach_port(ovs_vport_ovsl(dp, OVSP_LOCAL));
1309err_destroy_ports_array: 1297err_destroy_ports_array:
1298 ovs_unlock();
1310 kfree(dp->ports); 1299 kfree(dp->ports);
1311err_destroy_percpu: 1300err_destroy_percpu:
1312 free_percpu(dp->stats_percpu); 1301 free_percpu(dp->stats_percpu);
@@ -1315,8 +1304,8 @@ err_destroy_table:
1315err_free_dp: 1304err_free_dp:
1316 release_net(ovs_dp_get_net(dp)); 1305 release_net(ovs_dp_get_net(dp));
1317 kfree(dp); 1306 kfree(dp);
1318err_unlock_ovs: 1307err_free_reply:
1319 ovs_unlock(); 1308 kfree_skb(reply);
1320err: 1309err:
1321 return err; 1310 return err;
1322} 1311}
@@ -1354,16 +1343,19 @@ static int ovs_dp_cmd_del(struct sk_buff *skb, struct genl_info *info)
1354 struct datapath *dp; 1343 struct datapath *dp;
1355 int err; 1344 int err;
1356 1345
1346 reply = ovs_dp_cmd_alloc_info(info);
1347 if (!reply)
1348 return -ENOMEM;
1349
1357 ovs_lock(); 1350 ovs_lock();
1358 dp = lookup_datapath(sock_net(skb->sk), info->userhdr, info->attrs); 1351 dp = lookup_datapath(sock_net(skb->sk), info->userhdr, info->attrs);
1359 err = PTR_ERR(dp); 1352 err = PTR_ERR(dp);
1360 if (IS_ERR(dp)) 1353 if (IS_ERR(dp))
1361 goto unlock; 1354 goto err_unlock_free;
1362 1355
1363 reply = ovs_dp_cmd_build_info(dp, info, OVS_DP_CMD_DEL); 1356 err = ovs_dp_cmd_fill_info(dp, reply, info->snd_portid,
1364 err = PTR_ERR(reply); 1357 info->snd_seq, 0, OVS_DP_CMD_DEL);
1365 if (IS_ERR(reply)) 1358 BUG_ON(err < 0);
1366 goto unlock;
1367 1359
1368 __dp_destroy(dp); 1360 __dp_destroy(dp);
1369 ovs_unlock(); 1361 ovs_unlock();
@@ -1371,8 +1363,10 @@ static int ovs_dp_cmd_del(struct sk_buff *skb, struct genl_info *info)
1371 ovs_notify(&dp_datapath_genl_family, reply, info); 1363 ovs_notify(&dp_datapath_genl_family, reply, info);
1372 1364
1373 return 0; 1365 return 0;
1374unlock: 1366
1367err_unlock_free:
1375 ovs_unlock(); 1368 ovs_unlock();
1369 kfree_skb(reply);
1376 return err; 1370 return err;
1377} 1371}
1378 1372
@@ -1382,29 +1376,30 @@ static int ovs_dp_cmd_set(struct sk_buff *skb, struct genl_info *info)
1382 struct datapath *dp; 1376 struct datapath *dp;
1383 int err; 1377 int err;
1384 1378
1379 reply = ovs_dp_cmd_alloc_info(info);
1380 if (!reply)
1381 return -ENOMEM;
1382
1385 ovs_lock(); 1383 ovs_lock();
1386 dp = lookup_datapath(sock_net(skb->sk), info->userhdr, info->attrs); 1384 dp = lookup_datapath(sock_net(skb->sk), info->userhdr, info->attrs);
1387 err = PTR_ERR(dp); 1385 err = PTR_ERR(dp);
1388 if (IS_ERR(dp)) 1386 if (IS_ERR(dp))
1389 goto unlock; 1387 goto err_unlock_free;
1390 1388
1391 ovs_dp_change(dp, info->attrs); 1389 ovs_dp_change(dp, info->attrs);
1392 1390
1393 reply = ovs_dp_cmd_build_info(dp, info, OVS_DP_CMD_NEW); 1391 err = ovs_dp_cmd_fill_info(dp, reply, info->snd_portid,
1394 if (IS_ERR(reply)) { 1392 info->snd_seq, 0, OVS_DP_CMD_NEW);
1395 err = PTR_ERR(reply); 1393 BUG_ON(err < 0);
1396 genl_set_err(&dp_datapath_genl_family, sock_net(skb->sk), 0,
1397 0, err);
1398 err = 0;
1399 goto unlock;
1400 }
1401 1394
1402 ovs_unlock(); 1395 ovs_unlock();
1403 ovs_notify(&dp_datapath_genl_family, reply, info); 1396 ovs_notify(&dp_datapath_genl_family, reply, info);
1404 1397
1405 return 0; 1398 return 0;
1406unlock: 1399
1400err_unlock_free:
1407 ovs_unlock(); 1401 ovs_unlock();
1402 kfree_skb(reply);
1408 return err; 1403 return err;
1409} 1404}
1410 1405
@@ -1414,24 +1409,26 @@ static int ovs_dp_cmd_get(struct sk_buff *skb, struct genl_info *info)
1414 struct datapath *dp; 1409 struct datapath *dp;
1415 int err; 1410 int err;
1416 1411
1417 ovs_lock(); 1412 reply = ovs_dp_cmd_alloc_info(info);
1413 if (!reply)
1414 return -ENOMEM;
1415
1416 rcu_read_lock();
1418 dp = lookup_datapath(sock_net(skb->sk), info->userhdr, info->attrs); 1417 dp = lookup_datapath(sock_net(skb->sk), info->userhdr, info->attrs);
1419 if (IS_ERR(dp)) { 1418 if (IS_ERR(dp)) {
1420 err = PTR_ERR(dp); 1419 err = PTR_ERR(dp);
1421 goto unlock; 1420 goto err_unlock_free;
1422 }
1423
1424 reply = ovs_dp_cmd_build_info(dp, info, OVS_DP_CMD_NEW);
1425 if (IS_ERR(reply)) {
1426 err = PTR_ERR(reply);
1427 goto unlock;
1428 } 1421 }
1422 err = ovs_dp_cmd_fill_info(dp, reply, info->snd_portid,
1423 info->snd_seq, 0, OVS_DP_CMD_NEW);
1424 BUG_ON(err < 0);
1425 rcu_read_unlock();
1429 1426
1430 ovs_unlock();
1431 return genlmsg_reply(reply, info); 1427 return genlmsg_reply(reply, info);
1432 1428
1433unlock: 1429err_unlock_free:
1434 ovs_unlock(); 1430 rcu_read_unlock();
1431 kfree_skb(reply);
1435 return err; 1432 return err;
1436} 1433}
1437 1434
@@ -1544,7 +1541,12 @@ error:
1544 return err; 1541 return err;
1545} 1542}
1546 1543
1547/* Called with ovs_mutex or RCU read lock. */ 1544static struct sk_buff *ovs_vport_cmd_alloc_info(void)
1545{
1546 return nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1547}
1548
1549/* Called with ovs_mutex, only via ovs_dp_notify_wq(). */
1548struct sk_buff *ovs_vport_cmd_build_info(struct vport *vport, u32 portid, 1550struct sk_buff *ovs_vport_cmd_build_info(struct vport *vport, u32 portid,
1549 u32 seq, u8 cmd) 1551 u32 seq, u8 cmd)
1550{ 1552{
@@ -1606,33 +1608,35 @@ static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info)
1606 u32 port_no; 1608 u32 port_no;
1607 int err; 1609 int err;
1608 1610
1609 err = -EINVAL;
1610 if (!a[OVS_VPORT_ATTR_NAME] || !a[OVS_VPORT_ATTR_TYPE] || 1611 if (!a[OVS_VPORT_ATTR_NAME] || !a[OVS_VPORT_ATTR_TYPE] ||
1611 !a[OVS_VPORT_ATTR_UPCALL_PID]) 1612 !a[OVS_VPORT_ATTR_UPCALL_PID])
1612 goto exit; 1613 return -EINVAL;
1614
1615 port_no = a[OVS_VPORT_ATTR_PORT_NO]
1616 ? nla_get_u32(a[OVS_VPORT_ATTR_PORT_NO]) : 0;
1617 if (port_no >= DP_MAX_PORTS)
1618 return -EFBIG;
1619
1620 reply = ovs_vport_cmd_alloc_info();
1621 if (!reply)
1622 return -ENOMEM;
1613 1623
1614 ovs_lock(); 1624 ovs_lock();
1615 dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex); 1625 dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
1616 err = -ENODEV; 1626 err = -ENODEV;
1617 if (!dp) 1627 if (!dp)
1618 goto exit_unlock; 1628 goto exit_unlock_free;
1619
1620 if (a[OVS_VPORT_ATTR_PORT_NO]) {
1621 port_no = nla_get_u32(a[OVS_VPORT_ATTR_PORT_NO]);
1622
1623 err = -EFBIG;
1624 if (port_no >= DP_MAX_PORTS)
1625 goto exit_unlock;
1626 1629
1630 if (port_no) {
1627 vport = ovs_vport_ovsl(dp, port_no); 1631 vport = ovs_vport_ovsl(dp, port_no);
1628 err = -EBUSY; 1632 err = -EBUSY;
1629 if (vport) 1633 if (vport)
1630 goto exit_unlock; 1634 goto exit_unlock_free;
1631 } else { 1635 } else {
1632 for (port_no = 1; ; port_no++) { 1636 for (port_no = 1; ; port_no++) {
1633 if (port_no >= DP_MAX_PORTS) { 1637 if (port_no >= DP_MAX_PORTS) {
1634 err = -EFBIG; 1638 err = -EFBIG;
1635 goto exit_unlock; 1639 goto exit_unlock_free;
1636 } 1640 }
1637 vport = ovs_vport_ovsl(dp, port_no); 1641 vport = ovs_vport_ovsl(dp, port_no);
1638 if (!vport) 1642 if (!vport)
@@ -1650,22 +1654,19 @@ static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info)
1650 vport = new_vport(&parms); 1654 vport = new_vport(&parms);
1651 err = PTR_ERR(vport); 1655 err = PTR_ERR(vport);
1652 if (IS_ERR(vport)) 1656 if (IS_ERR(vport))
1653 goto exit_unlock; 1657 goto exit_unlock_free;
1654 1658
1655 err = 0; 1659 err = ovs_vport_cmd_fill_info(vport, reply, info->snd_portid,
1656 reply = ovs_vport_cmd_build_info(vport, info->snd_portid, info->snd_seq, 1660 info->snd_seq, 0, OVS_VPORT_CMD_NEW);
1657 OVS_VPORT_CMD_NEW); 1661 BUG_ON(err < 0);
1658 if (IS_ERR(reply)) { 1662 ovs_unlock();
1659 err = PTR_ERR(reply);
1660 ovs_dp_detach_port(vport);
1661 goto exit_unlock;
1662 }
1663 1663
1664 ovs_notify(&dp_vport_genl_family, reply, info); 1664 ovs_notify(&dp_vport_genl_family, reply, info);
1665 return 0;
1665 1666
1666exit_unlock: 1667exit_unlock_free:
1667 ovs_unlock(); 1668 ovs_unlock();
1668exit: 1669 kfree_skb(reply);
1669 return err; 1670 return err;
1670} 1671}
1671 1672
@@ -1676,28 +1677,26 @@ static int ovs_vport_cmd_set(struct sk_buff *skb, struct genl_info *info)
1676 struct vport *vport; 1677 struct vport *vport;
1677 int err; 1678 int err;
1678 1679
1680 reply = ovs_vport_cmd_alloc_info();
1681 if (!reply)
1682 return -ENOMEM;
1683
1679 ovs_lock(); 1684 ovs_lock();
1680 vport = lookup_vport(sock_net(skb->sk), info->userhdr, a); 1685 vport = lookup_vport(sock_net(skb->sk), info->userhdr, a);
1681 err = PTR_ERR(vport); 1686 err = PTR_ERR(vport);
1682 if (IS_ERR(vport)) 1687 if (IS_ERR(vport))
1683 goto exit_unlock; 1688 goto exit_unlock_free;
1684 1689
1685 if (a[OVS_VPORT_ATTR_TYPE] && 1690 if (a[OVS_VPORT_ATTR_TYPE] &&
1686 nla_get_u32(a[OVS_VPORT_ATTR_TYPE]) != vport->ops->type) { 1691 nla_get_u32(a[OVS_VPORT_ATTR_TYPE]) != vport->ops->type) {
1687 err = -EINVAL; 1692 err = -EINVAL;
1688 goto exit_unlock; 1693 goto exit_unlock_free;
1689 }
1690
1691 reply = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1692 if (!reply) {
1693 err = -ENOMEM;
1694 goto exit_unlock;
1695 } 1694 }
1696 1695
1697 if (a[OVS_VPORT_ATTR_OPTIONS]) { 1696 if (a[OVS_VPORT_ATTR_OPTIONS]) {
1698 err = ovs_vport_set_options(vport, a[OVS_VPORT_ATTR_OPTIONS]); 1697 err = ovs_vport_set_options(vport, a[OVS_VPORT_ATTR_OPTIONS]);
1699 if (err) 1698 if (err)
1700 goto exit_free; 1699 goto exit_unlock_free;
1701 } 1700 }
1702 1701
1703 if (a[OVS_VPORT_ATTR_UPCALL_PID]) 1702 if (a[OVS_VPORT_ATTR_UPCALL_PID])
@@ -1711,10 +1710,9 @@ static int ovs_vport_cmd_set(struct sk_buff *skb, struct genl_info *info)
1711 ovs_notify(&dp_vport_genl_family, reply, info); 1710 ovs_notify(&dp_vport_genl_family, reply, info);
1712 return 0; 1711 return 0;
1713 1712
1714exit_free: 1713exit_unlock_free:
1715 kfree_skb(reply);
1716exit_unlock:
1717 ovs_unlock(); 1714 ovs_unlock();
1715 kfree_skb(reply);
1718 return err; 1716 return err;
1719} 1717}
1720 1718
@@ -1725,30 +1723,33 @@ static int ovs_vport_cmd_del(struct sk_buff *skb, struct genl_info *info)
1725 struct vport *vport; 1723 struct vport *vport;
1726 int err; 1724 int err;
1727 1725
1726 reply = ovs_vport_cmd_alloc_info();
1727 if (!reply)
1728 return -ENOMEM;
1729
1728 ovs_lock(); 1730 ovs_lock();
1729 vport = lookup_vport(sock_net(skb->sk), info->userhdr, a); 1731 vport = lookup_vport(sock_net(skb->sk), info->userhdr, a);
1730 err = PTR_ERR(vport); 1732 err = PTR_ERR(vport);
1731 if (IS_ERR(vport)) 1733 if (IS_ERR(vport))
1732 goto exit_unlock; 1734 goto exit_unlock_free;
1733 1735
1734 if (vport->port_no == OVSP_LOCAL) { 1736 if (vport->port_no == OVSP_LOCAL) {
1735 err = -EINVAL; 1737 err = -EINVAL;
1736 goto exit_unlock; 1738 goto exit_unlock_free;
1737 } 1739 }
1738 1740
1739 reply = ovs_vport_cmd_build_info(vport, info->snd_portid, 1741 err = ovs_vport_cmd_fill_info(vport, reply, info->snd_portid,
1740 info->snd_seq, OVS_VPORT_CMD_DEL); 1742 info->snd_seq, 0, OVS_VPORT_CMD_DEL);
1741 err = PTR_ERR(reply); 1743 BUG_ON(err < 0);
1742 if (IS_ERR(reply))
1743 goto exit_unlock;
1744
1745 err = 0;
1746 ovs_dp_detach_port(vport); 1744 ovs_dp_detach_port(vport);
1745 ovs_unlock();
1747 1746
1748 ovs_notify(&dp_vport_genl_family, reply, info); 1747 ovs_notify(&dp_vport_genl_family, reply, info);
1748 return 0;
1749 1749
1750exit_unlock: 1750exit_unlock_free:
1751 ovs_unlock(); 1751 ovs_unlock();
1752 kfree_skb(reply);
1752 return err; 1753 return err;
1753} 1754}
1754 1755
@@ -1760,24 +1761,25 @@ static int ovs_vport_cmd_get(struct sk_buff *skb, struct genl_info *info)
1760 struct vport *vport; 1761 struct vport *vport;
1761 int err; 1762 int err;
1762 1763
1764 reply = ovs_vport_cmd_alloc_info();
1765 if (!reply)
1766 return -ENOMEM;
1767
1763 rcu_read_lock(); 1768 rcu_read_lock();
1764 vport = lookup_vport(sock_net(skb->sk), ovs_header, a); 1769 vport = lookup_vport(sock_net(skb->sk), ovs_header, a);
1765 err = PTR_ERR(vport); 1770 err = PTR_ERR(vport);
1766 if (IS_ERR(vport)) 1771 if (IS_ERR(vport))
1767 goto exit_unlock; 1772 goto exit_unlock_free;
1768 1773 err = ovs_vport_cmd_fill_info(vport, reply, info->snd_portid,
1769 reply = ovs_vport_cmd_build_info(vport, info->snd_portid, 1774 info->snd_seq, 0, OVS_VPORT_CMD_NEW);
1770 info->snd_seq, OVS_VPORT_CMD_NEW); 1775 BUG_ON(err < 0);
1771 err = PTR_ERR(reply);
1772 if (IS_ERR(reply))
1773 goto exit_unlock;
1774
1775 rcu_read_unlock(); 1776 rcu_read_unlock();
1776 1777
1777 return genlmsg_reply(reply, info); 1778 return genlmsg_reply(reply, info);
1778 1779
1779exit_unlock: 1780exit_unlock_free:
1780 rcu_read_unlock(); 1781 rcu_read_unlock();
1782 kfree_skb(reply);
1781 return err; 1783 return err;
1782} 1784}
1783 1785