diff options
Diffstat (limited to 'net/openvswitch/datapath.c')
-rw-r--r-- | net/openvswitch/datapath.c | 32 |
1 files changed, 21 insertions, 11 deletions
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c index df4692826ead..8601b320b443 100644 --- a/net/openvswitch/datapath.c +++ b/net/openvswitch/datapath.c | |||
@@ -55,6 +55,7 @@ | |||
55 | 55 | ||
56 | #include "datapath.h" | 56 | #include "datapath.h" |
57 | #include "flow.h" | 57 | #include "flow.h" |
58 | #include "flow_table.h" | ||
58 | #include "flow_netlink.h" | 59 | #include "flow_netlink.h" |
59 | #include "vport-internal_dev.h" | 60 | #include "vport-internal_dev.h" |
60 | #include "vport-netdev.h" | 61 | #include "vport-netdev.h" |
@@ -160,7 +161,6 @@ static void destroy_dp_rcu(struct rcu_head *rcu) | |||
160 | { | 161 | { |
161 | struct datapath *dp = container_of(rcu, struct datapath, rcu); | 162 | struct datapath *dp = container_of(rcu, struct datapath, rcu); |
162 | 163 | ||
163 | ovs_flow_tbl_destroy(&dp->table); | ||
164 | free_percpu(dp->stats_percpu); | 164 | free_percpu(dp->stats_percpu); |
165 | release_net(ovs_dp_get_net(dp)); | 165 | release_net(ovs_dp_get_net(dp)); |
166 | kfree(dp->ports); | 166 | kfree(dp->ports); |
@@ -466,6 +466,14 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb, | |||
466 | 466 | ||
467 | skb_zerocopy(user_skb, skb, skb->len, hlen); | 467 | skb_zerocopy(user_skb, skb, skb->len, hlen); |
468 | 468 | ||
469 | /* Pad OVS_PACKET_ATTR_PACKET if linear copy was performed */ | ||
470 | if (!(dp->user_features & OVS_DP_F_UNALIGNED)) { | ||
471 | size_t plen = NLA_ALIGN(user_skb->len) - user_skb->len; | ||
472 | |||
473 | if (plen > 0) | ||
474 | memset(skb_put(user_skb, plen), 0, plen); | ||
475 | } | ||
476 | |||
469 | ((struct nlmsghdr *) user_skb->data)->nlmsg_len = user_skb->len; | 477 | ((struct nlmsghdr *) user_skb->data)->nlmsg_len = user_skb->len; |
470 | 478 | ||
471 | err = genlmsg_unicast(ovs_dp_get_net(dp), user_skb, upcall_info->portid); | 479 | err = genlmsg_unicast(ovs_dp_get_net(dp), user_skb, upcall_info->portid); |
@@ -852,11 +860,8 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) | |||
852 | goto err_unlock_ovs; | 860 | goto err_unlock_ovs; |
853 | 861 | ||
854 | /* The unmasked key has to be the same for flow updates. */ | 862 | /* The unmasked key has to be the same for flow updates. */ |
855 | error = -EINVAL; | 863 | if (!ovs_flow_cmp_unmasked_key(flow, &match)) |
856 | if (!ovs_flow_cmp_unmasked_key(flow, &match)) { | ||
857 | OVS_NLERR("Flow modification message rejected, unmasked key does not match.\n"); | ||
858 | goto err_unlock_ovs; | 864 | goto err_unlock_ovs; |
859 | } | ||
860 | 865 | ||
861 | /* Update actions. */ | 866 | /* Update actions. */ |
862 | old_acts = ovsl_dereference(flow->sf_acts); | 867 | old_acts = ovsl_dereference(flow->sf_acts); |
@@ -1079,6 +1084,7 @@ static size_t ovs_dp_cmd_msg_size(void) | |||
1079 | msgsize += nla_total_size(IFNAMSIZ); | 1084 | msgsize += nla_total_size(IFNAMSIZ); |
1080 | msgsize += nla_total_size(sizeof(struct ovs_dp_stats)); | 1085 | msgsize += nla_total_size(sizeof(struct ovs_dp_stats)); |
1081 | msgsize += nla_total_size(sizeof(struct ovs_dp_megaflow_stats)); | 1086 | msgsize += nla_total_size(sizeof(struct ovs_dp_megaflow_stats)); |
1087 | msgsize += nla_total_size(sizeof(u32)); /* OVS_DP_ATTR_USER_FEATURES */ | ||
1082 | 1088 | ||
1083 | return msgsize; | 1089 | return msgsize; |
1084 | } | 1090 | } |
@@ -1168,7 +1174,7 @@ static void ovs_dp_reset_user_features(struct sk_buff *skb, struct genl_info *in | |||
1168 | struct datapath *dp; | 1174 | struct datapath *dp; |
1169 | 1175 | ||
1170 | dp = lookup_datapath(sock_net(skb->sk), info->userhdr, info->attrs); | 1176 | dp = lookup_datapath(sock_net(skb->sk), info->userhdr, info->attrs); |
1171 | if (!dp) | 1177 | if (IS_ERR(dp)) |
1172 | return; | 1178 | return; |
1173 | 1179 | ||
1174 | WARN(dp->user_features, "Dropping previously announced user features\n"); | 1180 | WARN(dp->user_features, "Dropping previously announced user features\n"); |
@@ -1279,7 +1285,7 @@ err_destroy_ports_array: | |||
1279 | err_destroy_percpu: | 1285 | err_destroy_percpu: |
1280 | free_percpu(dp->stats_percpu); | 1286 | free_percpu(dp->stats_percpu); |
1281 | err_destroy_table: | 1287 | err_destroy_table: |
1282 | ovs_flow_tbl_destroy(&dp->table); | 1288 | ovs_flow_tbl_destroy(&dp->table, false); |
1283 | err_free_dp: | 1289 | err_free_dp: |
1284 | release_net(ovs_dp_get_net(dp)); | 1290 | release_net(ovs_dp_get_net(dp)); |
1285 | kfree(dp); | 1291 | kfree(dp); |
@@ -1306,10 +1312,13 @@ static void __dp_destroy(struct datapath *dp) | |||
1306 | list_del_rcu(&dp->list_node); | 1312 | list_del_rcu(&dp->list_node); |
1307 | 1313 | ||
1308 | /* OVSP_LOCAL is datapath internal port. We need to make sure that | 1314 | /* OVSP_LOCAL is datapath internal port. We need to make sure that |
1309 | * all port in datapath are destroyed first before freeing datapath. | 1315 | * all ports in datapath are destroyed first before freeing datapath. |
1310 | */ | 1316 | */ |
1311 | ovs_dp_detach_port(ovs_vport_ovsl(dp, OVSP_LOCAL)); | 1317 | ovs_dp_detach_port(ovs_vport_ovsl(dp, OVSP_LOCAL)); |
1312 | 1318 | ||
1319 | /* RCU destroy the flow table */ | ||
1320 | ovs_flow_tbl_destroy(&dp->table, true); | ||
1321 | |||
1313 | call_rcu(&dp->rcu, destroy_dp_rcu); | 1322 | call_rcu(&dp->rcu, destroy_dp_rcu); |
1314 | } | 1323 | } |
1315 | 1324 | ||
@@ -1753,11 +1762,12 @@ static int ovs_vport_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb) | |||
1753 | int bucket = cb->args[0], skip = cb->args[1]; | 1762 | int bucket = cb->args[0], skip = cb->args[1]; |
1754 | int i, j = 0; | 1763 | int i, j = 0; |
1755 | 1764 | ||
1765 | rcu_read_lock(); | ||
1756 | dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex); | 1766 | dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex); |
1757 | if (!dp) | 1767 | if (!dp) { |
1768 | rcu_read_unlock(); | ||
1758 | return -ENODEV; | 1769 | return -ENODEV; |
1759 | 1770 | } | |
1760 | rcu_read_lock(); | ||
1761 | for (i = bucket; i < DP_VPORT_HASH_BUCKETS; i++) { | 1771 | for (i = bucket; i < DP_VPORT_HASH_BUCKETS; i++) { |
1762 | struct vport *vport; | 1772 | struct vport *vport; |
1763 | 1773 | ||