diff options
author | Andy Zhou <azhou@nicira.com> | 2013-08-07 23:01:00 -0400 |
---|---|---|
committer | Jesse Gross <jesse@nicira.com> | 2013-08-23 19:43:07 -0400 |
commit | 03f0d916aa0317592dda11bd17c7357858719b6c (patch) | |
tree | 436f94d9c4846cadfa73ee0822f44a6383f3a2f3 /net/openvswitch/datapath.c | |
parent | 3fa34de67861abfc4846ccec886ca549d46ae56c (diff) |
openvswitch: Mega flow implementation
Add wildcarded flow support in kernel datapath.
Wildcarded flow can improve OVS flow set up performance by avoid sending
matching new flows to the user space program. The exact performance boost
will largely dependent on wildcarded flow hit rate.
In case all new flows hits wildcard flows, the flow set up rate is
within 5% of that of linux bridge module.
Pravin has made significant contributions to this patch. Including API
clean ups and bug fixes.
Signed-off-by: Pravin B Shelar <pshelar@nicira.com>
Signed-off-by: Andy Zhou <azhou@nicira.com>
Signed-off-by: Jesse Gross <jesse@nicira.com>
Diffstat (limited to 'net/openvswitch/datapath.c')
-rw-r--r-- | net/openvswitch/datapath.c | 140 |
1 files changed, 100 insertions, 40 deletions
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c index 9d97ef3c9830..d29cd9aa4a67 100644 --- a/net/openvswitch/datapath.c +++ b/net/openvswitch/datapath.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2007-2012 Nicira, Inc. | 2 | * Copyright (c) 2007-2013 Nicira, Inc. |
3 | * | 3 | * |
4 | * This program is free software; you can redistribute it and/or | 4 | * This program is free software; you can redistribute it and/or |
5 | * modify it under the terms of version 2 of the GNU General Public | 5 | * modify it under the terms of version 2 of the GNU General Public |
@@ -165,7 +165,7 @@ static void destroy_dp_rcu(struct rcu_head *rcu) | |||
165 | { | 165 | { |
166 | struct datapath *dp = container_of(rcu, struct datapath, rcu); | 166 | struct datapath *dp = container_of(rcu, struct datapath, rcu); |
167 | 167 | ||
168 | ovs_flow_tbl_destroy((__force struct flow_table *)dp->table); | 168 | ovs_flow_tbl_destroy((__force struct flow_table *)dp->table, false); |
169 | free_percpu(dp->stats_percpu); | 169 | free_percpu(dp->stats_percpu); |
170 | release_net(ovs_dp_get_net(dp)); | 170 | release_net(ovs_dp_get_net(dp)); |
171 | kfree(dp->ports); | 171 | kfree(dp->ports); |
@@ -226,19 +226,18 @@ void ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb) | |||
226 | struct sw_flow_key key; | 226 | struct sw_flow_key key; |
227 | u64 *stats_counter; | 227 | u64 *stats_counter; |
228 | int error; | 228 | int error; |
229 | int key_len; | ||
230 | 229 | ||
231 | stats = this_cpu_ptr(dp->stats_percpu); | 230 | stats = this_cpu_ptr(dp->stats_percpu); |
232 | 231 | ||
233 | /* Extract flow from 'skb' into 'key'. */ | 232 | /* Extract flow from 'skb' into 'key'. */ |
234 | error = ovs_flow_extract(skb, p->port_no, &key, &key_len); | 233 | error = ovs_flow_extract(skb, p->port_no, &key); |
235 | if (unlikely(error)) { | 234 | if (unlikely(error)) { |
236 | kfree_skb(skb); | 235 | kfree_skb(skb); |
237 | return; | 236 | return; |
238 | } | 237 | } |
239 | 238 | ||
240 | /* Look up flow. */ | 239 | /* Look up flow. */ |
241 | flow = ovs_flow_tbl_lookup(rcu_dereference(dp->table), &key, key_len); | 240 | flow = ovs_flow_lookup(rcu_dereference(dp->table), &key); |
242 | if (unlikely(!flow)) { | 241 | if (unlikely(!flow)) { |
243 | struct dp_upcall_info upcall; | 242 | struct dp_upcall_info upcall; |
244 | 243 | ||
@@ -253,6 +252,7 @@ void ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb) | |||
253 | } | 252 | } |
254 | 253 | ||
255 | OVS_CB(skb)->flow = flow; | 254 | OVS_CB(skb)->flow = flow; |
255 | OVS_CB(skb)->pkt_key = &key; | ||
256 | 256 | ||
257 | stats_counter = &stats->n_hit; | 257 | stats_counter = &stats->n_hit; |
258 | ovs_flow_used(OVS_CB(skb)->flow, skb); | 258 | ovs_flow_used(OVS_CB(skb)->flow, skb); |
@@ -435,7 +435,7 @@ static int queue_userspace_packet(struct net *net, int dp_ifindex, | |||
435 | upcall->dp_ifindex = dp_ifindex; | 435 | upcall->dp_ifindex = dp_ifindex; |
436 | 436 | ||
437 | nla = nla_nest_start(user_skb, OVS_PACKET_ATTR_KEY); | 437 | nla = nla_nest_start(user_skb, OVS_PACKET_ATTR_KEY); |
438 | ovs_flow_to_nlattrs(upcall_info->key, user_skb); | 438 | ovs_flow_to_nlattrs(upcall_info->key, upcall_info->key, user_skb); |
439 | nla_nest_end(user_skb, nla); | 439 | nla_nest_end(user_skb, nla); |
440 | 440 | ||
441 | if (upcall_info->userdata) | 441 | if (upcall_info->userdata) |
@@ -468,7 +468,7 @@ static int flush_flows(struct datapath *dp) | |||
468 | 468 | ||
469 | rcu_assign_pointer(dp->table, new_table); | 469 | rcu_assign_pointer(dp->table, new_table); |
470 | 470 | ||
471 | ovs_flow_tbl_deferred_destroy(old_table); | 471 | ovs_flow_tbl_destroy(old_table, true); |
472 | return 0; | 472 | return 0; |
473 | } | 473 | } |
474 | 474 | ||
@@ -611,10 +611,12 @@ static int validate_tp_port(const struct sw_flow_key *flow_key) | |||
611 | static int validate_and_copy_set_tun(const struct nlattr *attr, | 611 | static int validate_and_copy_set_tun(const struct nlattr *attr, |
612 | struct sw_flow_actions **sfa) | 612 | struct sw_flow_actions **sfa) |
613 | { | 613 | { |
614 | struct ovs_key_ipv4_tunnel tun_key; | 614 | struct sw_flow_match match; |
615 | struct sw_flow_key key; | ||
615 | int err, start; | 616 | int err, start; |
616 | 617 | ||
617 | err = ovs_ipv4_tun_from_nlattr(nla_data(attr), &tun_key); | 618 | ovs_match_init(&match, &key, NULL); |
619 | err = ovs_ipv4_tun_from_nlattr(nla_data(attr), &match, false); | ||
618 | if (err) | 620 | if (err) |
619 | return err; | 621 | return err; |
620 | 622 | ||
@@ -622,7 +624,8 @@ static int validate_and_copy_set_tun(const struct nlattr *attr, | |||
622 | if (start < 0) | 624 | if (start < 0) |
623 | return start; | 625 | return start; |
624 | 626 | ||
625 | err = add_action(sfa, OVS_KEY_ATTR_IPV4_TUNNEL, &tun_key, sizeof(tun_key)); | 627 | err = add_action(sfa, OVS_KEY_ATTR_IPV4_TUNNEL, &match.key->tun_key, |
628 | sizeof(match.key->tun_key)); | ||
626 | add_nested_action_end(*sfa, start); | 629 | add_nested_action_end(*sfa, start); |
627 | 630 | ||
628 | return err; | 631 | return err; |
@@ -857,7 +860,6 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info) | |||
857 | struct ethhdr *eth; | 860 | struct ethhdr *eth; |
858 | int len; | 861 | int len; |
859 | int err; | 862 | int err; |
860 | int key_len; | ||
861 | 863 | ||
862 | err = -EINVAL; | 864 | err = -EINVAL; |
863 | if (!a[OVS_PACKET_ATTR_PACKET] || !a[OVS_PACKET_ATTR_KEY] || | 865 | if (!a[OVS_PACKET_ATTR_PACKET] || !a[OVS_PACKET_ATTR_KEY] || |
@@ -890,11 +892,11 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info) | |||
890 | if (IS_ERR(flow)) | 892 | if (IS_ERR(flow)) |
891 | goto err_kfree_skb; | 893 | goto err_kfree_skb; |
892 | 894 | ||
893 | err = ovs_flow_extract(packet, -1, &flow->key, &key_len); | 895 | err = ovs_flow_extract(packet, -1, &flow->key); |
894 | if (err) | 896 | if (err) |
895 | goto err_flow_free; | 897 | goto err_flow_free; |
896 | 898 | ||
897 | err = ovs_flow_metadata_from_nlattrs(flow, key_len, a[OVS_PACKET_ATTR_KEY]); | 899 | err = ovs_flow_metadata_from_nlattrs(flow, a[OVS_PACKET_ATTR_KEY]); |
898 | if (err) | 900 | if (err) |
899 | goto err_flow_free; | 901 | goto err_flow_free; |
900 | acts = ovs_flow_actions_alloc(nla_len(a[OVS_PACKET_ATTR_ACTIONS])); | 902 | acts = ovs_flow_actions_alloc(nla_len(a[OVS_PACKET_ATTR_ACTIONS])); |
@@ -908,6 +910,7 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info) | |||
908 | goto err_flow_free; | 910 | goto err_flow_free; |
909 | 911 | ||
910 | OVS_CB(packet)->flow = flow; | 912 | OVS_CB(packet)->flow = flow; |
913 | OVS_CB(packet)->pkt_key = &flow->key; | ||
911 | packet->priority = flow->key.phy.priority; | 914 | packet->priority = flow->key.phy.priority; |
912 | packet->mark = flow->key.phy.skb_mark; | 915 | packet->mark = flow->key.phy.skb_mark; |
913 | 916 | ||
@@ -922,13 +925,13 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info) | |||
922 | local_bh_enable(); | 925 | local_bh_enable(); |
923 | rcu_read_unlock(); | 926 | rcu_read_unlock(); |
924 | 927 | ||
925 | ovs_flow_free(flow); | 928 | ovs_flow_free(flow, false); |
926 | return err; | 929 | return err; |
927 | 930 | ||
928 | err_unlock: | 931 | err_unlock: |
929 | rcu_read_unlock(); | 932 | rcu_read_unlock(); |
930 | err_flow_free: | 933 | err_flow_free: |
931 | ovs_flow_free(flow); | 934 | ovs_flow_free(flow, false); |
932 | err_kfree_skb: | 935 | err_kfree_skb: |
933 | kfree_skb(packet); | 936 | kfree_skb(packet); |
934 | err: | 937 | err: |
@@ -1045,7 +1048,8 @@ static int set_action_to_attr(const struct nlattr *a, struct sk_buff *skb) | |||
1045 | if (!start) | 1048 | if (!start) |
1046 | return -EMSGSIZE; | 1049 | return -EMSGSIZE; |
1047 | 1050 | ||
1048 | err = ovs_ipv4_tun_to_nlattr(skb, nla_data(ovs_key)); | 1051 | err = ovs_ipv4_tun_to_nlattr(skb, nla_data(ovs_key), |
1052 | nla_data(ovs_key)); | ||
1049 | if (err) | 1053 | if (err) |
1050 | return err; | 1054 | return err; |
1051 | nla_nest_end(skb, start); | 1055 | nla_nest_end(skb, start); |
@@ -1093,6 +1097,7 @@ static size_t ovs_flow_cmd_msg_size(const struct sw_flow_actions *acts) | |||
1093 | { | 1097 | { |
1094 | return NLMSG_ALIGN(sizeof(struct ovs_header)) | 1098 | return NLMSG_ALIGN(sizeof(struct ovs_header)) |
1095 | + nla_total_size(key_attr_size()) /* OVS_FLOW_ATTR_KEY */ | 1099 | + nla_total_size(key_attr_size()) /* OVS_FLOW_ATTR_KEY */ |
1100 | + nla_total_size(key_attr_size()) /* OVS_FLOW_ATTR_MASK */ | ||
1096 | + nla_total_size(sizeof(struct ovs_flow_stats)) /* OVS_FLOW_ATTR_STATS */ | 1101 | + nla_total_size(sizeof(struct ovs_flow_stats)) /* OVS_FLOW_ATTR_STATS */ |
1097 | + nla_total_size(1) /* OVS_FLOW_ATTR_TCP_FLAGS */ | 1102 | + nla_total_size(1) /* OVS_FLOW_ATTR_TCP_FLAGS */ |
1098 | + nla_total_size(8) /* OVS_FLOW_ATTR_USED */ | 1103 | + nla_total_size(8) /* OVS_FLOW_ATTR_USED */ |
@@ -1119,12 +1124,25 @@ static int ovs_flow_cmd_fill_info(struct sw_flow *flow, struct datapath *dp, | |||
1119 | 1124 | ||
1120 | ovs_header->dp_ifindex = get_dpifindex(dp); | 1125 | ovs_header->dp_ifindex = get_dpifindex(dp); |
1121 | 1126 | ||
1127 | /* Fill flow key. */ | ||
1122 | nla = nla_nest_start(skb, OVS_FLOW_ATTR_KEY); | 1128 | nla = nla_nest_start(skb, OVS_FLOW_ATTR_KEY); |
1123 | if (!nla) | 1129 | if (!nla) |
1124 | goto nla_put_failure; | 1130 | goto nla_put_failure; |
1125 | err = ovs_flow_to_nlattrs(&flow->key, skb); | 1131 | |
1132 | err = ovs_flow_to_nlattrs(&flow->unmasked_key, | ||
1133 | &flow->unmasked_key, skb); | ||
1134 | if (err) | ||
1135 | goto error; | ||
1136 | nla_nest_end(skb, nla); | ||
1137 | |||
1138 | nla = nla_nest_start(skb, OVS_FLOW_ATTR_MASK); | ||
1139 | if (!nla) | ||
1140 | goto nla_put_failure; | ||
1141 | |||
1142 | err = ovs_flow_to_nlattrs(&flow->key, &flow->mask->key, skb); | ||
1126 | if (err) | 1143 | if (err) |
1127 | goto error; | 1144 | goto error; |
1145 | |||
1128 | nla_nest_end(skb, nla); | 1146 | nla_nest_end(skb, nla); |
1129 | 1147 | ||
1130 | spin_lock_bh(&flow->lock); | 1148 | spin_lock_bh(&flow->lock); |
@@ -1214,20 +1232,24 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) | |||
1214 | { | 1232 | { |
1215 | struct nlattr **a = info->attrs; | 1233 | struct nlattr **a = info->attrs; |
1216 | struct ovs_header *ovs_header = info->userhdr; | 1234 | struct ovs_header *ovs_header = info->userhdr; |
1217 | struct sw_flow_key key; | 1235 | struct sw_flow_key key, masked_key; |
1218 | struct sw_flow *flow; | 1236 | struct sw_flow *flow = NULL; |
1237 | struct sw_flow_mask mask; | ||
1219 | struct sk_buff *reply; | 1238 | struct sk_buff *reply; |
1220 | struct datapath *dp; | 1239 | struct datapath *dp; |
1221 | struct flow_table *table; | 1240 | struct flow_table *table; |
1222 | struct sw_flow_actions *acts = NULL; | 1241 | struct sw_flow_actions *acts = NULL; |
1242 | struct sw_flow_match match; | ||
1223 | int error; | 1243 | int error; |
1224 | int key_len; | ||
1225 | 1244 | ||
1226 | /* Extract key. */ | 1245 | /* Extract key. */ |
1227 | error = -EINVAL; | 1246 | error = -EINVAL; |
1228 | if (!a[OVS_FLOW_ATTR_KEY]) | 1247 | if (!a[OVS_FLOW_ATTR_KEY]) |
1229 | goto error; | 1248 | goto error; |
1230 | error = ovs_flow_from_nlattrs(&key, &key_len, a[OVS_FLOW_ATTR_KEY]); | 1249 | |
1250 | ovs_match_init(&match, &key, &mask); | ||
1251 | error = ovs_match_from_nlattrs(&match, | ||
1252 | a[OVS_FLOW_ATTR_KEY], a[OVS_FLOW_ATTR_MASK]); | ||
1231 | if (error) | 1253 | if (error) |
1232 | goto error; | 1254 | goto error; |
1233 | 1255 | ||
@@ -1238,9 +1260,13 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) | |||
1238 | if (IS_ERR(acts)) | 1260 | if (IS_ERR(acts)) |
1239 | goto error; | 1261 | goto error; |
1240 | 1262 | ||
1241 | error = validate_and_copy_actions(a[OVS_FLOW_ATTR_ACTIONS], &key, 0, &acts); | 1263 | ovs_flow_key_mask(&masked_key, &key, &mask); |
1242 | if (error) | 1264 | error = validate_and_copy_actions(a[OVS_FLOW_ATTR_ACTIONS], |
1265 | &masked_key, 0, &acts); | ||
1266 | if (error) { | ||
1267 | OVS_NLERR("Flow actions may not be safe on all matching packets.\n"); | ||
1243 | goto err_kfree; | 1268 | goto err_kfree; |
1269 | } | ||
1244 | } else if (info->genlhdr->cmd == OVS_FLOW_CMD_NEW) { | 1270 | } else if (info->genlhdr->cmd == OVS_FLOW_CMD_NEW) { |
1245 | error = -EINVAL; | 1271 | error = -EINVAL; |
1246 | goto error; | 1272 | goto error; |
@@ -1253,8 +1279,11 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) | |||
1253 | goto err_unlock_ovs; | 1279 | goto err_unlock_ovs; |
1254 | 1280 | ||
1255 | table = ovsl_dereference(dp->table); | 1281 | table = ovsl_dereference(dp->table); |
1256 | flow = ovs_flow_tbl_lookup(table, &key, key_len); | 1282 | |
1283 | /* Check if this is a duplicate flow */ | ||
1284 | flow = ovs_flow_lookup(table, &key); | ||
1257 | if (!flow) { | 1285 | if (!flow) { |
1286 | struct sw_flow_mask *mask_p; | ||
1258 | /* Bail out if we're not allowed to create a new flow. */ | 1287 | /* Bail out if we're not allowed to create a new flow. */ |
1259 | error = -ENOENT; | 1288 | error = -ENOENT; |
1260 | if (info->genlhdr->cmd == OVS_FLOW_CMD_SET) | 1289 | if (info->genlhdr->cmd == OVS_FLOW_CMD_SET) |
@@ -1267,7 +1296,7 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) | |||
1267 | new_table = ovs_flow_tbl_expand(table); | 1296 | new_table = ovs_flow_tbl_expand(table); |
1268 | if (!IS_ERR(new_table)) { | 1297 | if (!IS_ERR(new_table)) { |
1269 | rcu_assign_pointer(dp->table, new_table); | 1298 | rcu_assign_pointer(dp->table, new_table); |
1270 | ovs_flow_tbl_deferred_destroy(table); | 1299 | ovs_flow_tbl_destroy(table, true); |
1271 | table = ovsl_dereference(dp->table); | 1300 | table = ovsl_dereference(dp->table); |
1272 | } | 1301 | } |
1273 | } | 1302 | } |
@@ -1280,14 +1309,30 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) | |||
1280 | } | 1309 | } |
1281 | clear_stats(flow); | 1310 | clear_stats(flow); |
1282 | 1311 | ||
1312 | flow->key = masked_key; | ||
1313 | flow->unmasked_key = key; | ||
1314 | |||
1315 | /* Make sure mask is unique in the system */ | ||
1316 | mask_p = ovs_sw_flow_mask_find(table, &mask); | ||
1317 | if (!mask_p) { | ||
1318 | /* Allocate a new mask if none exsits. */ | ||
1319 | mask_p = ovs_sw_flow_mask_alloc(); | ||
1320 | if (!mask_p) | ||
1321 | goto err_flow_free; | ||
1322 | mask_p->key = mask.key; | ||
1323 | mask_p->range = mask.range; | ||
1324 | ovs_sw_flow_mask_insert(table, mask_p); | ||
1325 | } | ||
1326 | |||
1327 | ovs_sw_flow_mask_add_ref(mask_p); | ||
1328 | flow->mask = mask_p; | ||
1283 | rcu_assign_pointer(flow->sf_acts, acts); | 1329 | rcu_assign_pointer(flow->sf_acts, acts); |
1284 | 1330 | ||
1285 | /* Put flow in bucket. */ | 1331 | /* Put flow in bucket. */ |
1286 | ovs_flow_tbl_insert(table, flow, &key, key_len); | 1332 | ovs_flow_insert(table, flow); |
1287 | 1333 | ||
1288 | reply = ovs_flow_cmd_build_info(flow, dp, info->snd_portid, | 1334 | reply = ovs_flow_cmd_build_info(flow, dp, info->snd_portid, |
1289 | info->snd_seq, | 1335 | info->snd_seq, OVS_FLOW_CMD_NEW); |
1290 | OVS_FLOW_CMD_NEW); | ||
1291 | } else { | 1336 | } else { |
1292 | /* We found a matching flow. */ | 1337 | /* We found a matching flow. */ |
1293 | struct sw_flow_actions *old_acts; | 1338 | struct sw_flow_actions *old_acts; |
@@ -1303,6 +1348,13 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) | |||
1303 | info->nlhdr->nlmsg_flags & (NLM_F_CREATE | NLM_F_EXCL)) | 1348 | info->nlhdr->nlmsg_flags & (NLM_F_CREATE | NLM_F_EXCL)) |
1304 | goto err_unlock_ovs; | 1349 | goto err_unlock_ovs; |
1305 | 1350 | ||
1351 | /* The unmasked key has to be the same for flow updates. */ | ||
1352 | error = -EINVAL; | ||
1353 | if (!ovs_flow_cmp_unmasked_key(flow, &key, match.range.end)) { | ||
1354 | OVS_NLERR("Flow modification message rejected, unmasked key does not match.\n"); | ||
1355 | goto err_unlock_ovs; | ||
1356 | } | ||
1357 | |||
1306 | /* Update actions. */ | 1358 | /* Update actions. */ |
1307 | old_acts = ovsl_dereference(flow->sf_acts); | 1359 | old_acts = ovsl_dereference(flow->sf_acts); |
1308 | rcu_assign_pointer(flow->sf_acts, acts); | 1360 | rcu_assign_pointer(flow->sf_acts, acts); |
@@ -1327,6 +1379,8 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) | |||
1327 | ovs_dp_flow_multicast_group.id, PTR_ERR(reply)); | 1379 | ovs_dp_flow_multicast_group.id, PTR_ERR(reply)); |
1328 | return 0; | 1380 | return 0; |
1329 | 1381 | ||
1382 | err_flow_free: | ||
1383 | ovs_flow_free(flow, false); | ||
1330 | err_unlock_ovs: | 1384 | err_unlock_ovs: |
1331 | ovs_unlock(); | 1385 | ovs_unlock(); |
1332 | err_kfree: | 1386 | err_kfree: |
@@ -1344,12 +1398,16 @@ static int ovs_flow_cmd_get(struct sk_buff *skb, struct genl_info *info) | |||
1344 | struct sw_flow *flow; | 1398 | struct sw_flow *flow; |
1345 | struct datapath *dp; | 1399 | struct datapath *dp; |
1346 | struct flow_table *table; | 1400 | struct flow_table *table; |
1401 | struct sw_flow_match match; | ||
1347 | int err; | 1402 | int err; |
1348 | int key_len; | ||
1349 | 1403 | ||
1350 | if (!a[OVS_FLOW_ATTR_KEY]) | 1404 | if (!a[OVS_FLOW_ATTR_KEY]) { |
1405 | OVS_NLERR("Flow get message rejected, Key attribute missing.\n"); | ||
1351 | return -EINVAL; | 1406 | return -EINVAL; |
1352 | err = ovs_flow_from_nlattrs(&key, &key_len, a[OVS_FLOW_ATTR_KEY]); | 1407 | } |
1408 | |||
1409 | ovs_match_init(&match, &key, NULL); | ||
1410 | err = ovs_match_from_nlattrs(&match, a[OVS_FLOW_ATTR_KEY], NULL); | ||
1353 | if (err) | 1411 | if (err) |
1354 | return err; | 1412 | return err; |
1355 | 1413 | ||
@@ -1361,7 +1419,7 @@ static int ovs_flow_cmd_get(struct sk_buff *skb, struct genl_info *info) | |||
1361 | } | 1419 | } |
1362 | 1420 | ||
1363 | table = ovsl_dereference(dp->table); | 1421 | table = ovsl_dereference(dp->table); |
1364 | flow = ovs_flow_tbl_lookup(table, &key, key_len); | 1422 | flow = ovs_flow_lookup_unmasked_key(table, &match); |
1365 | if (!flow) { | 1423 | if (!flow) { |
1366 | err = -ENOENT; | 1424 | err = -ENOENT; |
1367 | goto unlock; | 1425 | goto unlock; |
@@ -1390,8 +1448,8 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info) | |||
1390 | struct sw_flow *flow; | 1448 | struct sw_flow *flow; |
1391 | struct datapath *dp; | 1449 | struct datapath *dp; |
1392 | struct flow_table *table; | 1450 | struct flow_table *table; |
1451 | struct sw_flow_match match; | ||
1393 | int err; | 1452 | int err; |
1394 | int key_len; | ||
1395 | 1453 | ||
1396 | ovs_lock(); | 1454 | ovs_lock(); |
1397 | dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex); | 1455 | dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex); |
@@ -1404,12 +1462,14 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info) | |||
1404 | err = flush_flows(dp); | 1462 | err = flush_flows(dp); |
1405 | goto unlock; | 1463 | goto unlock; |
1406 | } | 1464 | } |
1407 | err = ovs_flow_from_nlattrs(&key, &key_len, a[OVS_FLOW_ATTR_KEY]); | 1465 | |
1466 | ovs_match_init(&match, &key, NULL); | ||
1467 | err = ovs_match_from_nlattrs(&match, a[OVS_FLOW_ATTR_KEY], NULL); | ||
1408 | if (err) | 1468 | if (err) |
1409 | goto unlock; | 1469 | goto unlock; |
1410 | 1470 | ||
1411 | table = ovsl_dereference(dp->table); | 1471 | table = ovsl_dereference(dp->table); |
1412 | flow = ovs_flow_tbl_lookup(table, &key, key_len); | 1472 | flow = ovs_flow_lookup_unmasked_key(table, &match); |
1413 | if (!flow) { | 1473 | if (!flow) { |
1414 | err = -ENOENT; | 1474 | err = -ENOENT; |
1415 | goto unlock; | 1475 | goto unlock; |
@@ -1421,13 +1481,13 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info) | |||
1421 | goto unlock; | 1481 | goto unlock; |
1422 | } | 1482 | } |
1423 | 1483 | ||
1424 | ovs_flow_tbl_remove(table, flow); | 1484 | ovs_flow_remove(table, flow); |
1425 | 1485 | ||
1426 | err = ovs_flow_cmd_fill_info(flow, dp, reply, info->snd_portid, | 1486 | err = ovs_flow_cmd_fill_info(flow, dp, reply, info->snd_portid, |
1427 | info->snd_seq, 0, OVS_FLOW_CMD_DEL); | 1487 | info->snd_seq, 0, OVS_FLOW_CMD_DEL); |
1428 | BUG_ON(err < 0); | 1488 | BUG_ON(err < 0); |
1429 | 1489 | ||
1430 | ovs_flow_deferred_free(flow); | 1490 | ovs_flow_free(flow, true); |
1431 | ovs_unlock(); | 1491 | ovs_unlock(); |
1432 | 1492 | ||
1433 | ovs_notify(reply, info, &ovs_dp_flow_multicast_group); | 1493 | ovs_notify(reply, info, &ovs_dp_flow_multicast_group); |
@@ -1457,7 +1517,7 @@ static int ovs_flow_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb) | |||
1457 | 1517 | ||
1458 | bucket = cb->args[0]; | 1518 | bucket = cb->args[0]; |
1459 | obj = cb->args[1]; | 1519 | obj = cb->args[1]; |
1460 | flow = ovs_flow_tbl_next(table, &bucket, &obj); | 1520 | flow = ovs_flow_dump_next(table, &bucket, &obj); |
1461 | if (!flow) | 1521 | if (!flow) |
1462 | break; | 1522 | break; |
1463 | 1523 | ||
@@ -1680,7 +1740,7 @@ err_destroy_ports_array: | |||
1680 | err_destroy_percpu: | 1740 | err_destroy_percpu: |
1681 | free_percpu(dp->stats_percpu); | 1741 | free_percpu(dp->stats_percpu); |
1682 | err_destroy_table: | 1742 | err_destroy_table: |
1683 | ovs_flow_tbl_destroy(ovsl_dereference(dp->table)); | 1743 | ovs_flow_tbl_destroy(ovsl_dereference(dp->table), false); |
1684 | err_free_dp: | 1744 | err_free_dp: |
1685 | release_net(ovs_dp_get_net(dp)); | 1745 | release_net(ovs_dp_get_net(dp)); |
1686 | kfree(dp); | 1746 | kfree(dp); |
@@ -2287,7 +2347,7 @@ static void rehash_flow_table(struct work_struct *work) | |||
2287 | new_table = ovs_flow_tbl_rehash(old_table); | 2347 | new_table = ovs_flow_tbl_rehash(old_table); |
2288 | if (!IS_ERR(new_table)) { | 2348 | if (!IS_ERR(new_table)) { |
2289 | rcu_assign_pointer(dp->table, new_table); | 2349 | rcu_assign_pointer(dp->table, new_table); |
2290 | ovs_flow_tbl_deferred_destroy(old_table); | 2350 | ovs_flow_tbl_destroy(old_table, true); |
2291 | } | 2351 | } |
2292 | } | 2352 | } |
2293 | } | 2353 | } |