aboutsummaryrefslogtreecommitdiffstats
path: root/net/openvswitch/datapath.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/openvswitch/datapath.c')
-rw-r--r--net/openvswitch/datapath.c110
1 files changed, 77 insertions, 33 deletions
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c
index cad39fca75a9..105a0b5adc51 100644
--- a/net/openvswitch/datapath.c
+++ b/net/openvswitch/datapath.c
@@ -116,7 +116,7 @@ static struct datapath *get_dp(struct net *net, int dp_ifindex)
116/* Must be called with rcu_read_lock or RTNL lock. */ 116/* Must be called with rcu_read_lock or RTNL lock. */
117const char *ovs_dp_name(const struct datapath *dp) 117const char *ovs_dp_name(const struct datapath *dp)
118{ 118{
119 struct vport *vport = rcu_dereference_rtnl(dp->ports[OVSP_LOCAL]); 119 struct vport *vport = ovs_vport_rtnl_rcu(dp, OVSP_LOCAL);
120 return vport->ops->get_name(vport); 120 return vport->ops->get_name(vport);
121} 121}
122 122
@@ -127,7 +127,7 @@ static int get_dpifindex(struct datapath *dp)
127 127
128 rcu_read_lock(); 128 rcu_read_lock();
129 129
130 local = rcu_dereference(dp->ports[OVSP_LOCAL]); 130 local = ovs_vport_rcu(dp, OVSP_LOCAL);
131 if (local) 131 if (local)
132 ifindex = local->ops->get_ifindex(local); 132 ifindex = local->ops->get_ifindex(local);
133 else 133 else
@@ -145,9 +145,30 @@ static void destroy_dp_rcu(struct rcu_head *rcu)
145 ovs_flow_tbl_destroy((__force struct flow_table *)dp->table); 145 ovs_flow_tbl_destroy((__force struct flow_table *)dp->table);
146 free_percpu(dp->stats_percpu); 146 free_percpu(dp->stats_percpu);
147 release_net(ovs_dp_get_net(dp)); 147 release_net(ovs_dp_get_net(dp));
148 kfree(dp->ports);
148 kfree(dp); 149 kfree(dp);
149} 150}
150 151
152static struct hlist_head *vport_hash_bucket(const struct datapath *dp,
153 u16 port_no)
154{
155 return &dp->ports[port_no & (DP_VPORT_HASH_BUCKETS - 1)];
156}
157
158struct vport *ovs_lookup_vport(const struct datapath *dp, u16 port_no)
159{
160 struct vport *vport;
161 struct hlist_node *n;
162 struct hlist_head *head;
163
164 head = vport_hash_bucket(dp, port_no);
165 hlist_for_each_entry_rcu(vport, n, head, dp_hash_node) {
166 if (vport->port_no == port_no)
167 return vport;
168 }
169 return NULL;
170}
171
151/* Called with RTNL lock and genl_lock. */ 172/* Called with RTNL lock and genl_lock. */
152static struct vport *new_vport(const struct vport_parms *parms) 173static struct vport *new_vport(const struct vport_parms *parms)
153{ 174{
@@ -156,9 +177,9 @@ static struct vport *new_vport(const struct vport_parms *parms)
156 vport = ovs_vport_add(parms); 177 vport = ovs_vport_add(parms);
157 if (!IS_ERR(vport)) { 178 if (!IS_ERR(vport)) {
158 struct datapath *dp = parms->dp; 179 struct datapath *dp = parms->dp;
180 struct hlist_head *head = vport_hash_bucket(dp, vport->port_no);
159 181
160 rcu_assign_pointer(dp->ports[parms->port_no], vport); 182 hlist_add_head_rcu(&vport->dp_hash_node, head);
161 list_add(&vport->node, &dp->port_list);
162 } 183 }
163 184
164 return vport; 185 return vport;
@@ -170,8 +191,7 @@ void ovs_dp_detach_port(struct vport *p)
170 ASSERT_RTNL(); 191 ASSERT_RTNL();
171 192
172 /* First drop references to device. */ 193 /* First drop references to device. */
173 list_del(&p->node); 194 hlist_del_rcu(&p->dp_hash_node);
174 rcu_assign_pointer(p->dp->ports[p->port_no], NULL);
175 195
176 /* Then destroy it. */ 196 /* Then destroy it. */
177 ovs_vport_del(p); 197 ovs_vport_del(p);
@@ -1248,7 +1268,7 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
1248 struct datapath *dp; 1268 struct datapath *dp;
1249 struct vport *vport; 1269 struct vport *vport;
1250 struct ovs_net *ovs_net; 1270 struct ovs_net *ovs_net;
1251 int err; 1271 int err, i;
1252 1272
1253 err = -EINVAL; 1273 err = -EINVAL;
1254 if (!a[OVS_DP_ATTR_NAME] || !a[OVS_DP_ATTR_UPCALL_PID]) 1274 if (!a[OVS_DP_ATTR_NAME] || !a[OVS_DP_ATTR_UPCALL_PID])
@@ -1261,7 +1281,6 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
1261 if (dp == NULL) 1281 if (dp == NULL)
1262 goto err_unlock_rtnl; 1282 goto err_unlock_rtnl;
1263 1283
1264 INIT_LIST_HEAD(&dp->port_list);
1265 ovs_dp_set_net(dp, hold_net(sock_net(skb->sk))); 1284 ovs_dp_set_net(dp, hold_net(sock_net(skb->sk)));
1266 1285
1267 /* Allocate table. */ 1286 /* Allocate table. */
@@ -1276,6 +1295,16 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
1276 goto err_destroy_table; 1295 goto err_destroy_table;
1277 } 1296 }
1278 1297
1298 dp->ports = kmalloc(DP_VPORT_HASH_BUCKETS * sizeof(struct hlist_head),
1299 GFP_KERNEL);
1300 if (!dp->ports) {
1301 err = -ENOMEM;
1302 goto err_destroy_percpu;
1303 }
1304
1305 for (i = 0; i < DP_VPORT_HASH_BUCKETS; i++)
1306 INIT_HLIST_HEAD(&dp->ports[i]);
1307
1279 /* Set up our datapath device. */ 1308 /* Set up our datapath device. */
1280 parms.name = nla_data(a[OVS_DP_ATTR_NAME]); 1309 parms.name = nla_data(a[OVS_DP_ATTR_NAME]);
1281 parms.type = OVS_VPORT_TYPE_INTERNAL; 1310 parms.type = OVS_VPORT_TYPE_INTERNAL;
@@ -1290,7 +1319,7 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
1290 if (err == -EBUSY) 1319 if (err == -EBUSY)
1291 err = -EEXIST; 1320 err = -EEXIST;
1292 1321
1293 goto err_destroy_percpu; 1322 goto err_destroy_ports_array;
1294 } 1323 }
1295 1324
1296 reply = ovs_dp_cmd_build_info(dp, info->snd_pid, 1325 reply = ovs_dp_cmd_build_info(dp, info->snd_pid,
@@ -1309,7 +1338,9 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
1309 return 0; 1338 return 0;
1310 1339
1311err_destroy_local_port: 1340err_destroy_local_port:
1312 ovs_dp_detach_port(rtnl_dereference(dp->ports[OVSP_LOCAL])); 1341 ovs_dp_detach_port(ovs_vport_rtnl(dp, OVSP_LOCAL));
1342err_destroy_ports_array:
1343 kfree(dp->ports);
1313err_destroy_percpu: 1344err_destroy_percpu:
1314 free_percpu(dp->stats_percpu); 1345 free_percpu(dp->stats_percpu);
1315err_destroy_table: 1346err_destroy_table:
@@ -1326,15 +1357,21 @@ err:
1326/* Called with genl_mutex. */ 1357/* Called with genl_mutex. */
1327static void __dp_destroy(struct datapath *dp) 1358static void __dp_destroy(struct datapath *dp)
1328{ 1359{
1329 struct vport *vport, *next_vport; 1360 int i;
1330 1361
1331 rtnl_lock(); 1362 rtnl_lock();
1332 list_for_each_entry_safe(vport, next_vport, &dp->port_list, node) 1363
1333 if (vport->port_no != OVSP_LOCAL) 1364 for (i = 0; i < DP_VPORT_HASH_BUCKETS; i++) {
1334 ovs_dp_detach_port(vport); 1365 struct vport *vport;
1366 struct hlist_node *node, *n;
1367
1368 hlist_for_each_entry_safe(vport, node, n, &dp->ports[i], dp_hash_node)
1369 if (vport->port_no != OVSP_LOCAL)
1370 ovs_dp_detach_port(vport);
1371 }
1335 1372
1336 list_del(&dp->list_node); 1373 list_del(&dp->list_node);
1337 ovs_dp_detach_port(rtnl_dereference(dp->ports[OVSP_LOCAL])); 1374 ovs_dp_detach_port(ovs_vport_rtnl(dp, OVSP_LOCAL));
1338 1375
1339 /* rtnl_unlock() will wait until all the references to devices that 1376 /* rtnl_unlock() will wait until all the references to devices that
1340 * are pending unregistration have been dropped. We do it here to 1377 * are pending unregistration have been dropped. We do it here to
@@ -1566,7 +1603,7 @@ static struct vport *lookup_vport(struct net *net,
1566 if (!dp) 1603 if (!dp)
1567 return ERR_PTR(-ENODEV); 1604 return ERR_PTR(-ENODEV);
1568 1605
1569 vport = rcu_dereference_rtnl(dp->ports[port_no]); 1606 vport = ovs_vport_rtnl_rcu(dp, port_no);
1570 if (!vport) 1607 if (!vport)
1571 return ERR_PTR(-ENOENT); 1608 return ERR_PTR(-ENOENT);
1572 return vport; 1609 return vport;
@@ -1603,7 +1640,7 @@ static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info)
1603 if (port_no >= DP_MAX_PORTS) 1640 if (port_no >= DP_MAX_PORTS)
1604 goto exit_unlock; 1641 goto exit_unlock;
1605 1642
1606 vport = rtnl_dereference(dp->ports[port_no]); 1643 vport = ovs_vport_rtnl_rcu(dp, port_no);
1607 err = -EBUSY; 1644 err = -EBUSY;
1608 if (vport) 1645 if (vport)
1609 goto exit_unlock; 1646 goto exit_unlock;
@@ -1613,7 +1650,7 @@ static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info)
1613 err = -EFBIG; 1650 err = -EFBIG;
1614 goto exit_unlock; 1651 goto exit_unlock;
1615 } 1652 }
1616 vport = rtnl_dereference(dp->ports[port_no]); 1653 vport = ovs_vport_rtnl(dp, port_no);
1617 if (!vport) 1654 if (!vport)
1618 break; 1655 break;
1619 } 1656 }
@@ -1755,32 +1792,39 @@ static int ovs_vport_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb)
1755{ 1792{
1756 struct ovs_header *ovs_header = genlmsg_data(nlmsg_data(cb->nlh)); 1793 struct ovs_header *ovs_header = genlmsg_data(nlmsg_data(cb->nlh));
1757 struct datapath *dp; 1794 struct datapath *dp;
1758 u32 port_no; 1795 int bucket = cb->args[0], skip = cb->args[1];
1759 int retval; 1796 int i, j = 0;
1760 1797
1761 dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex); 1798 dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
1762 if (!dp) 1799 if (!dp)
1763 return -ENODEV; 1800 return -ENODEV;
1764 1801
1765 rcu_read_lock(); 1802 rcu_read_lock();
1766 for (port_no = cb->args[0]; port_no < DP_MAX_PORTS; port_no++) { 1803 for (i = bucket; i < DP_VPORT_HASH_BUCKETS; i++) {
1767 struct vport *vport; 1804 struct vport *vport;
1768 1805 struct hlist_node *n;
1769 vport = rcu_dereference(dp->ports[port_no]); 1806
1770 if (!vport) 1807 j = 0;
1771 continue; 1808 hlist_for_each_entry_rcu(vport, n, &dp->ports[i], dp_hash_node) {
1772 1809 if (j >= skip &&
1773 if (ovs_vport_cmd_fill_info(vport, skb, NETLINK_CB(cb->skb).pid, 1810 ovs_vport_cmd_fill_info(vport, skb,
1774 cb->nlh->nlmsg_seq, NLM_F_MULTI, 1811 NETLINK_CB(cb->skb).pid,
1775 OVS_VPORT_CMD_NEW) < 0) 1812 cb->nlh->nlmsg_seq,
1776 break; 1813 NLM_F_MULTI,
1814 OVS_VPORT_CMD_NEW) < 0)
1815 goto out;
1816
1817 j++;
1818 }
1819 skip = 0;
1777 } 1820 }
1821out:
1778 rcu_read_unlock(); 1822 rcu_read_unlock();
1779 1823
1780 cb->args[0] = port_no; 1824 cb->args[0] = i;
1781 retval = skb->len; 1825 cb->args[1] = j;
1782 1826
1783 return retval; 1827 return skb->len;
1784} 1828}
1785 1829
1786static struct genl_ops dp_vport_genl_ops[] = { 1830static struct genl_ops dp_vport_genl_ops[] = {