diff options
Diffstat (limited to 'net/openvswitch/datapath.c')
| -rw-r--r-- | net/openvswitch/datapath.c | 176 | 
1 files changed, 122 insertions, 54 deletions
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c index f2ed7600084e..2aa13bd7f2b2 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; | 
| @@ -709,6 +712,12 @@ static int validate_set(const struct nlattr *a, | |||
| 709 | 712 | ||
| 710 | return validate_tp_port(flow_key); | 713 | return validate_tp_port(flow_key); | 
| 711 | 714 | ||
| 715 | case OVS_KEY_ATTR_SCTP: | ||
| 716 | if (flow_key->ip.proto != IPPROTO_SCTP) | ||
| 717 | return -EINVAL; | ||
| 718 | |||
| 719 | return validate_tp_port(flow_key); | ||
| 720 | |||
| 712 | default: | 721 | default: | 
| 713 | return -EINVAL; | 722 | return -EINVAL; | 
| 714 | } | 723 | } | 
| @@ -857,7 +866,6 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info) | |||
| 857 | struct ethhdr *eth; | 866 | struct ethhdr *eth; | 
| 858 | int len; | 867 | int len; | 
| 859 | int err; | 868 | int err; | 
| 860 | int key_len; | ||
| 861 | 869 | ||
| 862 | err = -EINVAL; | 870 | err = -EINVAL; | 
| 863 | if (!a[OVS_PACKET_ATTR_PACKET] || !a[OVS_PACKET_ATTR_KEY] || | 871 | if (!a[OVS_PACKET_ATTR_PACKET] || !a[OVS_PACKET_ATTR_KEY] || | 
| @@ -890,11 +898,11 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info) | |||
| 890 | if (IS_ERR(flow)) | 898 | if (IS_ERR(flow)) | 
| 891 | goto err_kfree_skb; | 899 | goto err_kfree_skb; | 
| 892 | 900 | ||
| 893 | err = ovs_flow_extract(packet, -1, &flow->key, &key_len); | 901 | err = ovs_flow_extract(packet, -1, &flow->key); | 
| 894 | if (err) | 902 | if (err) | 
| 895 | goto err_flow_free; | 903 | goto err_flow_free; | 
| 896 | 904 | ||
| 897 | err = ovs_flow_metadata_from_nlattrs(flow, key_len, a[OVS_PACKET_ATTR_KEY]); | 905 | err = ovs_flow_metadata_from_nlattrs(flow, a[OVS_PACKET_ATTR_KEY]); | 
| 898 | if (err) | 906 | if (err) | 
| 899 | goto err_flow_free; | 907 | goto err_flow_free; | 
| 900 | acts = ovs_flow_actions_alloc(nla_len(a[OVS_PACKET_ATTR_ACTIONS])); | 908 | acts = ovs_flow_actions_alloc(nla_len(a[OVS_PACKET_ATTR_ACTIONS])); | 
| @@ -908,6 +916,7 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info) | |||
| 908 | goto err_flow_free; | 916 | goto err_flow_free; | 
| 909 | 917 | ||
| 910 | OVS_CB(packet)->flow = flow; | 918 | OVS_CB(packet)->flow = flow; | 
| 919 | OVS_CB(packet)->pkt_key = &flow->key; | ||
| 911 | packet->priority = flow->key.phy.priority; | 920 | packet->priority = flow->key.phy.priority; | 
| 912 | packet->mark = flow->key.phy.skb_mark; | 921 | packet->mark = flow->key.phy.skb_mark; | 
| 913 | 922 | ||
| @@ -922,13 +931,13 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info) | |||
| 922 | local_bh_enable(); | 931 | local_bh_enable(); | 
| 923 | rcu_read_unlock(); | 932 | rcu_read_unlock(); | 
| 924 | 933 | ||
| 925 | ovs_flow_free(flow); | 934 | ovs_flow_free(flow, false); | 
| 926 | return err; | 935 | return err; | 
| 927 | 936 | ||
| 928 | err_unlock: | 937 | err_unlock: | 
| 929 | rcu_read_unlock(); | 938 | rcu_read_unlock(); | 
| 930 | err_flow_free: | 939 | err_flow_free: | 
| 931 | ovs_flow_free(flow); | 940 | ovs_flow_free(flow, false); | 
| 932 | err_kfree_skb: | 941 | err_kfree_skb: | 
| 933 | kfree_skb(packet); | 942 | kfree_skb(packet); | 
| 934 | err: | 943 | err: | 
| @@ -951,9 +960,10 @@ static struct genl_ops dp_packet_genl_ops[] = { | |||
| 951 | 960 | ||
| 952 | static void get_dp_stats(struct datapath *dp, struct ovs_dp_stats *stats) | 961 | static void get_dp_stats(struct datapath *dp, struct ovs_dp_stats *stats) | 
| 953 | { | 962 | { | 
| 963 | struct flow_table *table; | ||
| 954 | int i; | 964 | int i; | 
| 955 | struct flow_table *table = ovsl_dereference(dp->table); | ||
| 956 | 965 | ||
| 966 | table = rcu_dereference_check(dp->table, lockdep_ovsl_is_held()); | ||
| 957 | stats->n_flows = ovs_flow_tbl_count(table); | 967 | stats->n_flows = ovs_flow_tbl_count(table); | 
| 958 | 968 | ||
| 959 | stats->n_hit = stats->n_missed = stats->n_lost = 0; | 969 | stats->n_hit = stats->n_missed = stats->n_lost = 0; | 
| @@ -1044,7 +1054,8 @@ static int set_action_to_attr(const struct nlattr *a, struct sk_buff *skb) | |||
| 1044 | if (!start) | 1054 | if (!start) | 
| 1045 | return -EMSGSIZE; | 1055 | return -EMSGSIZE; | 
| 1046 | 1056 | ||
| 1047 | err = ovs_ipv4_tun_to_nlattr(skb, nla_data(ovs_key)); | 1057 | err = ovs_ipv4_tun_to_nlattr(skb, nla_data(ovs_key), | 
| 1058 | nla_data(ovs_key)); | ||
| 1048 | if (err) | 1059 | if (err) | 
| 1049 | return err; | 1060 | return err; | 
| 1050 | nla_nest_end(skb, start); | 1061 | nla_nest_end(skb, start); | 
| @@ -1092,6 +1103,7 @@ static size_t ovs_flow_cmd_msg_size(const struct sw_flow_actions *acts) | |||
| 1092 | { | 1103 | { | 
| 1093 | return NLMSG_ALIGN(sizeof(struct ovs_header)) | 1104 | return NLMSG_ALIGN(sizeof(struct ovs_header)) | 
| 1094 | + nla_total_size(key_attr_size()) /* OVS_FLOW_ATTR_KEY */ | 1105 | + nla_total_size(key_attr_size()) /* OVS_FLOW_ATTR_KEY */ | 
| 1106 | + nla_total_size(key_attr_size()) /* OVS_FLOW_ATTR_MASK */ | ||
| 1095 | + nla_total_size(sizeof(struct ovs_flow_stats)) /* OVS_FLOW_ATTR_STATS */ | 1107 | + nla_total_size(sizeof(struct ovs_flow_stats)) /* OVS_FLOW_ATTR_STATS */ | 
| 1096 | + nla_total_size(1) /* OVS_FLOW_ATTR_TCP_FLAGS */ | 1108 | + nla_total_size(1) /* OVS_FLOW_ATTR_TCP_FLAGS */ | 
| 1097 | + nla_total_size(8) /* OVS_FLOW_ATTR_USED */ | 1109 | + nla_total_size(8) /* OVS_FLOW_ATTR_USED */ | 
| @@ -1104,7 +1116,6 @@ static int ovs_flow_cmd_fill_info(struct sw_flow *flow, struct datapath *dp, | |||
| 1104 | u32 seq, u32 flags, u8 cmd) | 1116 | u32 seq, u32 flags, u8 cmd) | 
| 1105 | { | 1117 | { | 
| 1106 | const int skb_orig_len = skb->len; | 1118 | const int skb_orig_len = skb->len; | 
| 1107 | const struct sw_flow_actions *sf_acts; | ||
| 1108 | struct nlattr *start; | 1119 | struct nlattr *start; | 
| 1109 | struct ovs_flow_stats stats; | 1120 | struct ovs_flow_stats stats; | 
| 1110 | struct ovs_header *ovs_header; | 1121 | struct ovs_header *ovs_header; | 
| @@ -1113,20 +1124,31 @@ static int ovs_flow_cmd_fill_info(struct sw_flow *flow, struct datapath *dp, | |||
| 1113 | u8 tcp_flags; | 1124 | u8 tcp_flags; | 
| 1114 | int err; | 1125 | int err; | 
| 1115 | 1126 | ||
| 1116 | sf_acts = ovsl_dereference(flow->sf_acts); | ||
| 1117 | |||
| 1118 | ovs_header = genlmsg_put(skb, portid, seq, &dp_flow_genl_family, flags, cmd); | 1127 | ovs_header = genlmsg_put(skb, portid, seq, &dp_flow_genl_family, flags, cmd); | 
| 1119 | if (!ovs_header) | 1128 | if (!ovs_header) | 
| 1120 | return -EMSGSIZE; | 1129 | return -EMSGSIZE; | 
| 1121 | 1130 | ||
| 1122 | ovs_header->dp_ifindex = get_dpifindex(dp); | 1131 | ovs_header->dp_ifindex = get_dpifindex(dp); | 
| 1123 | 1132 | ||
| 1133 | /* Fill flow key. */ | ||
| 1124 | nla = nla_nest_start(skb, OVS_FLOW_ATTR_KEY); | 1134 | nla = nla_nest_start(skb, OVS_FLOW_ATTR_KEY); | 
| 1125 | if (!nla) | 1135 | if (!nla) | 
| 1126 | goto nla_put_failure; | 1136 | goto nla_put_failure; | 
| 1127 | err = ovs_flow_to_nlattrs(&flow->key, skb); | 1137 | |
| 1138 | err = ovs_flow_to_nlattrs(&flow->unmasked_key, | ||
| 1139 | &flow->unmasked_key, skb); | ||
| 1140 | if (err) | ||
| 1141 | goto error; | ||
| 1142 | nla_nest_end(skb, nla); | ||
| 1143 | |||
| 1144 | nla = nla_nest_start(skb, OVS_FLOW_ATTR_MASK); | ||
| 1145 | if (!nla) | ||
| 1146 | goto nla_put_failure; | ||
| 1147 | |||
| 1148 | err = ovs_flow_to_nlattrs(&flow->key, &flow->mask->key, skb); | ||
| 1128 | if (err) | 1149 | if (err) | 
| 1129 | goto error; | 1150 | goto error; | 
| 1151 | |||
| 1130 | nla_nest_end(skb, nla); | 1152 | nla_nest_end(skb, nla); | 
| 1131 | 1153 | ||
| 1132 | spin_lock_bh(&flow->lock); | 1154 | spin_lock_bh(&flow->lock); | 
| @@ -1161,6 +1183,11 @@ static int ovs_flow_cmd_fill_info(struct sw_flow *flow, struct datapath *dp, | |||
| 1161 | */ | 1183 | */ | 
| 1162 | start = nla_nest_start(skb, OVS_FLOW_ATTR_ACTIONS); | 1184 | start = nla_nest_start(skb, OVS_FLOW_ATTR_ACTIONS); | 
| 1163 | if (start) { | 1185 | if (start) { | 
| 1186 | const struct sw_flow_actions *sf_acts; | ||
| 1187 | |||
| 1188 | sf_acts = rcu_dereference_check(flow->sf_acts, | ||
| 1189 | lockdep_ovsl_is_held()); | ||
| 1190 | |||
| 1164 | err = actions_to_attr(sf_acts->actions, sf_acts->actions_len, skb); | 1191 | err = actions_to_attr(sf_acts->actions, sf_acts->actions_len, skb); | 
| 1165 | if (!err) | 1192 | if (!err) | 
| 1166 | nla_nest_end(skb, start); | 1193 | nla_nest_end(skb, start); | 
| @@ -1211,20 +1238,24 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) | |||
| 1211 | { | 1238 | { | 
| 1212 | struct nlattr **a = info->attrs; | 1239 | struct nlattr **a = info->attrs; | 
| 1213 | struct ovs_header *ovs_header = info->userhdr; | 1240 | struct ovs_header *ovs_header = info->userhdr; | 
| 1214 | struct sw_flow_key key; | 1241 | struct sw_flow_key key, masked_key; | 
| 1215 | struct sw_flow *flow; | 1242 | struct sw_flow *flow = NULL; | 
| 1243 | struct sw_flow_mask mask; | ||
| 1216 | struct sk_buff *reply; | 1244 | struct sk_buff *reply; | 
| 1217 | struct datapath *dp; | 1245 | struct datapath *dp; | 
| 1218 | struct flow_table *table; | 1246 | struct flow_table *table; | 
| 1219 | struct sw_flow_actions *acts = NULL; | 1247 | struct sw_flow_actions *acts = NULL; | 
| 1248 | struct sw_flow_match match; | ||
| 1220 | int error; | 1249 | int error; | 
| 1221 | int key_len; | ||
| 1222 | 1250 | ||
| 1223 | /* Extract key. */ | 1251 | /* Extract key. */ | 
| 1224 | error = -EINVAL; | 1252 | error = -EINVAL; | 
| 1225 | if (!a[OVS_FLOW_ATTR_KEY]) | 1253 | if (!a[OVS_FLOW_ATTR_KEY]) | 
| 1226 | goto error; | 1254 | goto error; | 
| 1227 | error = ovs_flow_from_nlattrs(&key, &key_len, a[OVS_FLOW_ATTR_KEY]); | 1255 | |
| 1256 | ovs_match_init(&match, &key, &mask); | ||
| 1257 | error = ovs_match_from_nlattrs(&match, | ||
| 1258 | a[OVS_FLOW_ATTR_KEY], a[OVS_FLOW_ATTR_MASK]); | ||
| 1228 | if (error) | 1259 | if (error) | 
| 1229 | goto error; | 1260 | goto error; | 
| 1230 | 1261 | ||
| @@ -1235,9 +1266,13 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) | |||
| 1235 | if (IS_ERR(acts)) | 1266 | if (IS_ERR(acts)) | 
| 1236 | goto error; | 1267 | goto error; | 
| 1237 | 1268 | ||
| 1238 | error = validate_and_copy_actions(a[OVS_FLOW_ATTR_ACTIONS], &key, 0, &acts); | 1269 | ovs_flow_key_mask(&masked_key, &key, &mask); | 
| 1239 | if (error) | 1270 | error = validate_and_copy_actions(a[OVS_FLOW_ATTR_ACTIONS], | 
| 1271 | &masked_key, 0, &acts); | ||
| 1272 | if (error) { | ||
| 1273 | OVS_NLERR("Flow actions may not be safe on all matching packets.\n"); | ||
| 1240 | goto err_kfree; | 1274 | goto err_kfree; | 
| 1275 | } | ||
| 1241 | } else if (info->genlhdr->cmd == OVS_FLOW_CMD_NEW) { | 1276 | } else if (info->genlhdr->cmd == OVS_FLOW_CMD_NEW) { | 
| 1242 | error = -EINVAL; | 1277 | error = -EINVAL; | 
| 1243 | goto error; | 1278 | goto error; | 
| @@ -1250,8 +1285,11 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) | |||
| 1250 | goto err_unlock_ovs; | 1285 | goto err_unlock_ovs; | 
| 1251 | 1286 | ||
| 1252 | table = ovsl_dereference(dp->table); | 1287 | table = ovsl_dereference(dp->table); | 
| 1253 | flow = ovs_flow_tbl_lookup(table, &key, key_len); | 1288 | |
| 1289 | /* Check if this is a duplicate flow */ | ||
| 1290 | flow = ovs_flow_lookup(table, &key); | ||
| 1254 | if (!flow) { | 1291 | if (!flow) { | 
| 1292 | struct sw_flow_mask *mask_p; | ||
| 1255 | /* Bail out if we're not allowed to create a new flow. */ | 1293 | /* Bail out if we're not allowed to create a new flow. */ | 
| 1256 | error = -ENOENT; | 1294 | error = -ENOENT; | 
| 1257 | if (info->genlhdr->cmd == OVS_FLOW_CMD_SET) | 1295 | if (info->genlhdr->cmd == OVS_FLOW_CMD_SET) | 
| @@ -1264,7 +1302,7 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) | |||
| 1264 | new_table = ovs_flow_tbl_expand(table); | 1302 | new_table = ovs_flow_tbl_expand(table); | 
| 1265 | if (!IS_ERR(new_table)) { | 1303 | if (!IS_ERR(new_table)) { | 
| 1266 | rcu_assign_pointer(dp->table, new_table); | 1304 | rcu_assign_pointer(dp->table, new_table); | 
| 1267 | ovs_flow_tbl_deferred_destroy(table); | 1305 | ovs_flow_tbl_destroy(table, true); | 
| 1268 | table = ovsl_dereference(dp->table); | 1306 | table = ovsl_dereference(dp->table); | 
| 1269 | } | 1307 | } | 
| 1270 | } | 1308 | } | 
| @@ -1277,14 +1315,30 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) | |||
| 1277 | } | 1315 | } | 
| 1278 | clear_stats(flow); | 1316 | clear_stats(flow); | 
| 1279 | 1317 | ||
| 1318 | flow->key = masked_key; | ||
| 1319 | flow->unmasked_key = key; | ||
| 1320 | |||
| 1321 | /* Make sure mask is unique in the system */ | ||
| 1322 | mask_p = ovs_sw_flow_mask_find(table, &mask); | ||
| 1323 | if (!mask_p) { | ||
| 1324 | /* Allocate a new mask if none exsits. */ | ||
| 1325 | mask_p = ovs_sw_flow_mask_alloc(); | ||
| 1326 | if (!mask_p) | ||
| 1327 | goto err_flow_free; | ||
| 1328 | mask_p->key = mask.key; | ||
| 1329 | mask_p->range = mask.range; | ||
| 1330 | ovs_sw_flow_mask_insert(table, mask_p); | ||
| 1331 | } | ||
| 1332 | |||
| 1333 | ovs_sw_flow_mask_add_ref(mask_p); | ||
| 1334 | flow->mask = mask_p; | ||
| 1280 | rcu_assign_pointer(flow->sf_acts, acts); | 1335 | rcu_assign_pointer(flow->sf_acts, acts); | 
| 1281 | 1336 | ||
| 1282 | /* Put flow in bucket. */ | 1337 | /* Put flow in bucket. */ | 
| 1283 | ovs_flow_tbl_insert(table, flow, &key, key_len); | 1338 | ovs_flow_insert(table, flow); | 
| 1284 | 1339 | ||
| 1285 | reply = ovs_flow_cmd_build_info(flow, dp, info->snd_portid, | 1340 | reply = ovs_flow_cmd_build_info(flow, dp, info->snd_portid, | 
| 1286 | info->snd_seq, | 1341 | info->snd_seq, OVS_FLOW_CMD_NEW); | 
| 1287 | OVS_FLOW_CMD_NEW); | ||
| 1288 | } else { | 1342 | } else { | 
| 1289 | /* We found a matching flow. */ | 1343 | /* We found a matching flow. */ | 
| 1290 | struct sw_flow_actions *old_acts; | 1344 | struct sw_flow_actions *old_acts; | 
| @@ -1300,6 +1354,13 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) | |||
| 1300 | info->nlhdr->nlmsg_flags & (NLM_F_CREATE | NLM_F_EXCL)) | 1354 | info->nlhdr->nlmsg_flags & (NLM_F_CREATE | NLM_F_EXCL)) | 
| 1301 | goto err_unlock_ovs; | 1355 | goto err_unlock_ovs; | 
| 1302 | 1356 | ||
| 1357 | /* The unmasked key has to be the same for flow updates. */ | ||
| 1358 | error = -EINVAL; | ||
| 1359 | if (!ovs_flow_cmp_unmasked_key(flow, &key, match.range.end)) { | ||
| 1360 | OVS_NLERR("Flow modification message rejected, unmasked key does not match.\n"); | ||
| 1361 | goto err_unlock_ovs; | ||
| 1362 | } | ||
| 1363 | |||
| 1303 | /* Update actions. */ | 1364 | /* Update actions. */ | 
| 1304 | old_acts = ovsl_dereference(flow->sf_acts); | 1365 | old_acts = ovsl_dereference(flow->sf_acts); | 
| 1305 | rcu_assign_pointer(flow->sf_acts, acts); | 1366 | rcu_assign_pointer(flow->sf_acts, acts); | 
| @@ -1324,6 +1385,8 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) | |||
| 1324 | ovs_dp_flow_multicast_group.id, PTR_ERR(reply)); | 1385 | ovs_dp_flow_multicast_group.id, PTR_ERR(reply)); | 
| 1325 | return 0; | 1386 | return 0; | 
| 1326 | 1387 | ||
| 1388 | err_flow_free: | ||
| 1389 | ovs_flow_free(flow, false); | ||
| 1327 | err_unlock_ovs: | 1390 | err_unlock_ovs: | 
| 1328 | ovs_unlock(); | 1391 | ovs_unlock(); | 
| 1329 | err_kfree: | 1392 | err_kfree: | 
| @@ -1341,12 +1404,16 @@ static int ovs_flow_cmd_get(struct sk_buff *skb, struct genl_info *info) | |||
| 1341 | struct sw_flow *flow; | 1404 | struct sw_flow *flow; | 
| 1342 | struct datapath *dp; | 1405 | struct datapath *dp; | 
| 1343 | struct flow_table *table; | 1406 | struct flow_table *table; | 
| 1407 | struct sw_flow_match match; | ||
| 1344 | int err; | 1408 | int err; | 
| 1345 | int key_len; | ||
| 1346 | 1409 | ||
| 1347 | if (!a[OVS_FLOW_ATTR_KEY]) | 1410 | if (!a[OVS_FLOW_ATTR_KEY]) { | 
| 1411 | OVS_NLERR("Flow get message rejected, Key attribute missing.\n"); | ||
| 1348 | return -EINVAL; | 1412 | return -EINVAL; | 
| 1349 | err = ovs_flow_from_nlattrs(&key, &key_len, a[OVS_FLOW_ATTR_KEY]); | 1413 | } | 
| 1414 | |||
| 1415 | ovs_match_init(&match, &key, NULL); | ||
| 1416 | err = ovs_match_from_nlattrs(&match, a[OVS_FLOW_ATTR_KEY], NULL); | ||
| 1350 | if (err) | 1417 | if (err) | 
| 1351 | return err; | 1418 | return err; | 
| 1352 | 1419 | ||
| @@ -1358,7 +1425,7 @@ static int ovs_flow_cmd_get(struct sk_buff *skb, struct genl_info *info) | |||
| 1358 | } | 1425 | } | 
| 1359 | 1426 | ||
| 1360 | table = ovsl_dereference(dp->table); | 1427 | table = ovsl_dereference(dp->table); | 
| 1361 | flow = ovs_flow_tbl_lookup(table, &key, key_len); | 1428 | flow = ovs_flow_lookup_unmasked_key(table, &match); | 
| 1362 | if (!flow) { | 1429 | if (!flow) { | 
| 1363 | err = -ENOENT; | 1430 | err = -ENOENT; | 
| 1364 | goto unlock; | 1431 | goto unlock; | 
| @@ -1387,8 +1454,8 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info) | |||
| 1387 | struct sw_flow *flow; | 1454 | struct sw_flow *flow; | 
| 1388 | struct datapath *dp; | 1455 | struct datapath *dp; | 
| 1389 | struct flow_table *table; | 1456 | struct flow_table *table; | 
| 1457 | struct sw_flow_match match; | ||
| 1390 | int err; | 1458 | int err; | 
| 1391 | int key_len; | ||
| 1392 | 1459 | ||
| 1393 | ovs_lock(); | 1460 | ovs_lock(); | 
| 1394 | dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex); | 1461 | dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex); | 
| @@ -1401,12 +1468,14 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info) | |||
| 1401 | err = flush_flows(dp); | 1468 | err = flush_flows(dp); | 
| 1402 | goto unlock; | 1469 | goto unlock; | 
| 1403 | } | 1470 | } | 
| 1404 | err = ovs_flow_from_nlattrs(&key, &key_len, a[OVS_FLOW_ATTR_KEY]); | 1471 | |
| 1472 | ovs_match_init(&match, &key, NULL); | ||
| 1473 | err = ovs_match_from_nlattrs(&match, a[OVS_FLOW_ATTR_KEY], NULL); | ||
| 1405 | if (err) | 1474 | if (err) | 
| 1406 | goto unlock; | 1475 | goto unlock; | 
| 1407 | 1476 | ||
| 1408 | table = ovsl_dereference(dp->table); | 1477 | table = ovsl_dereference(dp->table); | 
| 1409 | flow = ovs_flow_tbl_lookup(table, &key, key_len); | 1478 | flow = ovs_flow_lookup_unmasked_key(table, &match); | 
| 1410 | if (!flow) { | 1479 | if (!flow) { | 
| 1411 | err = -ENOENT; | 1480 | err = -ENOENT; | 
| 1412 | goto unlock; | 1481 | goto unlock; | 
| @@ -1418,13 +1487,13 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info) | |||
| 1418 | goto unlock; | 1487 | goto unlock; | 
| 1419 | } | 1488 | } | 
| 1420 | 1489 | ||
| 1421 | ovs_flow_tbl_remove(table, flow); | 1490 | ovs_flow_remove(table, flow); | 
| 1422 | 1491 | ||
| 1423 | err = ovs_flow_cmd_fill_info(flow, dp, reply, info->snd_portid, | 1492 | err = ovs_flow_cmd_fill_info(flow, dp, reply, info->snd_portid, | 
| 1424 | info->snd_seq, 0, OVS_FLOW_CMD_DEL); | 1493 | info->snd_seq, 0, OVS_FLOW_CMD_DEL); | 
| 1425 | BUG_ON(err < 0); | 1494 | BUG_ON(err < 0); | 
| 1426 | 1495 | ||
| 1427 | ovs_flow_deferred_free(flow); | 1496 | ovs_flow_free(flow, true); | 
| 1428 | ovs_unlock(); | 1497 | ovs_unlock(); | 
| 1429 | 1498 | ||
| 1430 | ovs_notify(reply, info, &ovs_dp_flow_multicast_group); | 1499 | ovs_notify(reply, info, &ovs_dp_flow_multicast_group); | 
| @@ -1440,22 +1509,21 @@ static int ovs_flow_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb) | |||
| 1440 | struct datapath *dp; | 1509 | struct datapath *dp; | 
| 1441 | struct flow_table *table; | 1510 | struct flow_table *table; | 
| 1442 | 1511 | ||
| 1443 | ovs_lock(); | 1512 | rcu_read_lock(); | 
| 1444 | dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex); | 1513 | dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex); | 
| 1445 | if (!dp) { | 1514 | if (!dp) { | 
| 1446 | ovs_unlock(); | 1515 | rcu_read_unlock(); | 
| 1447 | return -ENODEV; | 1516 | return -ENODEV; | 
| 1448 | } | 1517 | } | 
| 1449 | 1518 | ||
| 1450 | table = ovsl_dereference(dp->table); | 1519 | table = rcu_dereference(dp->table); | 
| 1451 | |||
| 1452 | for (;;) { | 1520 | for (;;) { | 
| 1453 | struct sw_flow *flow; | 1521 | struct sw_flow *flow; | 
| 1454 | u32 bucket, obj; | 1522 | u32 bucket, obj; | 
| 1455 | 1523 | ||
| 1456 | bucket = cb->args[0]; | 1524 | bucket = cb->args[0]; | 
| 1457 | obj = cb->args[1]; | 1525 | obj = cb->args[1]; | 
| 1458 | flow = ovs_flow_tbl_next(table, &bucket, &obj); | 1526 | flow = ovs_flow_dump_next(table, &bucket, &obj); | 
| 1459 | if (!flow) | 1527 | if (!flow) | 
| 1460 | break; | 1528 | break; | 
| 1461 | 1529 | ||
| @@ -1468,7 +1536,7 @@ static int ovs_flow_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb) | |||
| 1468 | cb->args[0] = bucket; | 1536 | cb->args[0] = bucket; | 
| 1469 | cb->args[1] = obj; | 1537 | cb->args[1] = obj; | 
| 1470 | } | 1538 | } | 
| 1471 | ovs_unlock(); | 1539 | rcu_read_unlock(); | 
| 1472 | return skb->len; | 1540 | return skb->len; | 
| 1473 | } | 1541 | } | 
| 1474 | 1542 | ||
| @@ -1664,7 +1732,7 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info) | |||
| 1664 | goto err_destroy_local_port; | 1732 | goto err_destroy_local_port; | 
| 1665 | 1733 | ||
| 1666 | ovs_net = net_generic(ovs_dp_get_net(dp), ovs_net_id); | 1734 | ovs_net = net_generic(ovs_dp_get_net(dp), ovs_net_id); | 
| 1667 | list_add_tail(&dp->list_node, &ovs_net->dps); | 1735 | list_add_tail_rcu(&dp->list_node, &ovs_net->dps); | 
| 1668 | 1736 | ||
| 1669 | ovs_unlock(); | 1737 | ovs_unlock(); | 
| 1670 | 1738 | ||
| @@ -1678,7 +1746,7 @@ err_destroy_ports_array: | |||
| 1678 | err_destroy_percpu: | 1746 | err_destroy_percpu: | 
| 1679 | free_percpu(dp->stats_percpu); | 1747 | free_percpu(dp->stats_percpu); | 
| 1680 | err_destroy_table: | 1748 | err_destroy_table: | 
| 1681 | ovs_flow_tbl_destroy(ovsl_dereference(dp->table)); | 1749 | ovs_flow_tbl_destroy(ovsl_dereference(dp->table), false); | 
| 1682 | err_free_dp: | 1750 | err_free_dp: | 
| 1683 | release_net(ovs_dp_get_net(dp)); | 1751 | release_net(ovs_dp_get_net(dp)); | 
| 1684 | kfree(dp); | 1752 | kfree(dp); | 
| @@ -1702,7 +1770,7 @@ static void __dp_destroy(struct datapath *dp) | |||
| 1702 | ovs_dp_detach_port(vport); | 1770 | ovs_dp_detach_port(vport); | 
| 1703 | } | 1771 | } | 
| 1704 | 1772 | ||
| 1705 | list_del(&dp->list_node); | 1773 | list_del_rcu(&dp->list_node); | 
| 1706 | 1774 | ||
| 1707 | /* OVSP_LOCAL is datapath internal port. We need to make sure that | 1775 | /* OVSP_LOCAL is datapath internal port. We need to make sure that | 
| 1708 | * all port in datapath are destroyed first before freeing datapath. | 1776 | * all port in datapath are destroyed first before freeing datapath. | 
| @@ -1807,8 +1875,8 @@ static int ovs_dp_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb) | |||
| 1807 | int skip = cb->args[0]; | 1875 | int skip = cb->args[0]; | 
| 1808 | int i = 0; | 1876 | int i = 0; | 
| 1809 | 1877 | ||
| 1810 | ovs_lock(); | 1878 | rcu_read_lock(); | 
| 1811 | list_for_each_entry(dp, &ovs_net->dps, list_node) { | 1879 | list_for_each_entry_rcu(dp, &ovs_net->dps, list_node) { | 
| 1812 | if (i >= skip && | 1880 | if (i >= skip && | 
| 1813 | ovs_dp_cmd_fill_info(dp, skb, NETLINK_CB(cb->skb).portid, | 1881 | ovs_dp_cmd_fill_info(dp, skb, NETLINK_CB(cb->skb).portid, | 
| 1814 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | 1882 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | 
| @@ -1816,7 +1884,7 @@ static int ovs_dp_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb) | |||
| 1816 | break; | 1884 | break; | 
| 1817 | i++; | 1885 | i++; | 
| 1818 | } | 1886 | } | 
| 1819 | ovs_unlock(); | 1887 | rcu_read_unlock(); | 
| 1820 | 1888 | ||
| 1821 | cb->args[0] = i; | 1889 | cb->args[0] = i; | 
| 1822 | 1890 | ||
| @@ -2285,7 +2353,7 @@ static void rehash_flow_table(struct work_struct *work) | |||
| 2285 | new_table = ovs_flow_tbl_rehash(old_table); | 2353 | new_table = ovs_flow_tbl_rehash(old_table); | 
| 2286 | if (!IS_ERR(new_table)) { | 2354 | if (!IS_ERR(new_table)) { | 
| 2287 | rcu_assign_pointer(dp->table, new_table); | 2355 | rcu_assign_pointer(dp->table, new_table); | 
| 2288 | ovs_flow_tbl_deferred_destroy(old_table); | 2356 | ovs_flow_tbl_destroy(old_table, true); | 
| 2289 | } | 2357 | } | 
| 2290 | } | 2358 | } | 
| 2291 | } | 2359 | } | 
