aboutsummaryrefslogtreecommitdiffstats
path: root/net/openvswitch
diff options
context:
space:
mode:
authorJarno Rajahalme <jrajahalme@nicira.com>2014-05-05 18:22:25 -0400
committerPravin B Shelar <pshelar@nicira.com>2014-05-22 19:27:36 -0400
commit893f139b9a6c00c097b9082a90f3041cfb3a0d20 (patch)
treebcf6105306b58fe3ad44b12dc0ef51862d889bbe /net/openvswitch
parent37bdc87ba00dadd0156db77ba48224d042202435 (diff)
openvswitch: Minimize ovs_flow_cmd_new|set critical sections.
Signed-off-by: Jarno Rajahalme <jrajahalme@nicira.com> Signed-off-by: Pravin B Shelar <pshelar@nicira.com>
Diffstat (limited to 'net/openvswitch')
-rw-r--r--net/openvswitch/datapath.c192
1 files changed, 116 insertions, 76 deletions
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c
index 22665a6144fc..6bc9d94c8df2 100644
--- a/net/openvswitch/datapath.c
+++ b/net/openvswitch/datapath.c
@@ -796,8 +796,7 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info)
796{ 796{
797 struct nlattr **a = info->attrs; 797 struct nlattr **a = info->attrs;
798 struct ovs_header *ovs_header = info->userhdr; 798 struct ovs_header *ovs_header = info->userhdr;
799 struct sw_flow_key key, masked_key; 799 struct sw_flow *flow, *new_flow;
800 struct sw_flow *flow;
801 struct sw_flow_mask mask; 800 struct sw_flow_mask mask;
802 struct sk_buff *reply; 801 struct sk_buff *reply;
803 struct datapath *dp; 802 struct datapath *dp;
@@ -805,61 +804,77 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info)
805 struct sw_flow_match match; 804 struct sw_flow_match match;
806 int error; 805 int error;
807 806
808 /* Extract key. */ 807 /* Must have key and actions. */
809 error = -EINVAL; 808 error = -EINVAL;
810 if (!a[OVS_FLOW_ATTR_KEY]) 809 if (!a[OVS_FLOW_ATTR_KEY])
811 goto error; 810 goto error;
811 if (!a[OVS_FLOW_ATTR_ACTIONS])
812 goto error;
812 813
813 ovs_match_init(&match, &key, &mask); 814 /* Most of the time we need to allocate a new flow, do it before
815 * locking.
816 */
817 new_flow = ovs_flow_alloc();
818 if (IS_ERR(new_flow)) {
819 error = PTR_ERR(new_flow);
820 goto error;
821 }
822
823 /* Extract key. */
824 ovs_match_init(&match, &new_flow->unmasked_key, &mask);
814 error = ovs_nla_get_match(&match, 825 error = ovs_nla_get_match(&match,
815 a[OVS_FLOW_ATTR_KEY], a[OVS_FLOW_ATTR_MASK]); 826 a[OVS_FLOW_ATTR_KEY], a[OVS_FLOW_ATTR_MASK]);
816 if (error) 827 if (error)
817 goto error; 828 goto err_kfree_flow;
818 829
819 /* Validate actions. */ 830 ovs_flow_mask_key(&new_flow->key, &new_flow->unmasked_key, &mask);
820 error = -EINVAL;
821 if (!a[OVS_FLOW_ATTR_ACTIONS])
822 goto error;
823 831
832 /* Validate actions. */
824 acts = ovs_nla_alloc_flow_actions(nla_len(a[OVS_FLOW_ATTR_ACTIONS])); 833 acts = ovs_nla_alloc_flow_actions(nla_len(a[OVS_FLOW_ATTR_ACTIONS]));
825 error = PTR_ERR(acts); 834 error = PTR_ERR(acts);
826 if (IS_ERR(acts)) 835 if (IS_ERR(acts))
827 goto error; 836 goto err_kfree_flow;
828 837
829 ovs_flow_mask_key(&masked_key, &key, &mask); 838 error = ovs_nla_copy_actions(a[OVS_FLOW_ATTR_ACTIONS], &new_flow->key,
830 error = ovs_nla_copy_actions(a[OVS_FLOW_ATTR_ACTIONS], 839 0, &acts);
831 &masked_key, 0, &acts);
832 if (error) { 840 if (error) {
833 OVS_NLERR("Flow actions may not be safe on all matching packets.\n"); 841 OVS_NLERR("Flow actions may not be safe on all matching packets.\n");
834 goto err_kfree; 842 goto err_kfree_acts;
843 }
844
845 reply = ovs_flow_cmd_alloc_info(acts, info, false);
846 if (IS_ERR(reply)) {
847 error = PTR_ERR(reply);
848 goto err_kfree_acts;
835 } 849 }
836 850
837 ovs_lock(); 851 ovs_lock();
838 dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex); 852 dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
839 error = -ENODEV; 853 if (unlikely(!dp)) {
840 if (!dp) 854 error = -ENODEV;
841 goto err_unlock_ovs; 855 goto err_unlock_ovs;
842 856 }
843 /* Check if this is a duplicate flow */ 857 /* Check if this is a duplicate flow */
844 flow = ovs_flow_tbl_lookup(&dp->table, &key); 858 flow = ovs_flow_tbl_lookup(&dp->table, &new_flow->unmasked_key);
845 if (!flow) { 859 if (likely(!flow)) {
846 /* Allocate flow. */ 860 rcu_assign_pointer(new_flow->sf_acts, acts);
847 flow = ovs_flow_alloc();
848 if (IS_ERR(flow)) {
849 error = PTR_ERR(flow);
850 goto err_unlock_ovs;
851 }
852
853 flow->key = masked_key;
854 flow->unmasked_key = key;
855 rcu_assign_pointer(flow->sf_acts, acts);
856 861
857 /* Put flow in bucket. */ 862 /* Put flow in bucket. */
858 error = ovs_flow_tbl_insert(&dp->table, flow, &mask); 863 error = ovs_flow_tbl_insert(&dp->table, new_flow, &mask);
859 if (error) { 864 if (unlikely(error)) {
860 acts = NULL; 865 acts = NULL;
861 goto err_flow_free; 866 goto err_unlock_ovs;
862 } 867 }
868
869 if (unlikely(reply)) {
870 error = ovs_flow_cmd_fill_info(new_flow,
871 ovs_header->dp_ifindex,
872 reply, info->snd_portid,
873 info->snd_seq, 0,
874 OVS_FLOW_CMD_NEW);
875 BUG_ON(error < 0);
876 }
877 ovs_unlock();
863 } else { 878 } else {
864 struct sw_flow_actions *old_acts; 879 struct sw_flow_actions *old_acts;
865 880
@@ -869,39 +884,45 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info)
869 * request. We also accept NLM_F_EXCL in case that bug ever 884 * request. We also accept NLM_F_EXCL in case that bug ever
870 * gets fixed. 885 * gets fixed.
871 */ 886 */
872 error = -EEXIST; 887 if (unlikely(info->nlhdr->nlmsg_flags & (NLM_F_CREATE
873 if (info->nlhdr->nlmsg_flags & (NLM_F_CREATE | NLM_F_EXCL)) 888 | NLM_F_EXCL))) {
889 error = -EEXIST;
874 goto err_unlock_ovs; 890 goto err_unlock_ovs;
875 891 }
876 /* The unmasked key has to be the same for flow updates. */ 892 /* The unmasked key has to be the same for flow updates. */
877 if (!ovs_flow_cmp_unmasked_key(flow, &match)) 893 if (unlikely(!ovs_flow_cmp_unmasked_key(flow, &match))) {
894 error = -EEXIST;
878 goto err_unlock_ovs; 895 goto err_unlock_ovs;
879 896 }
880 /* Update actions. */ 897 /* Update actions. */
881 old_acts = ovsl_dereference(flow->sf_acts); 898 old_acts = ovsl_dereference(flow->sf_acts);
882 rcu_assign_pointer(flow->sf_acts, acts); 899 rcu_assign_pointer(flow->sf_acts, acts);
883 ovs_nla_free_flow_actions(old_acts);
884 }
885 900
886 reply = ovs_flow_cmd_build_info(flow, ovs_header->dp_ifindex, 901 if (unlikely(reply)) {
887 info, OVS_FLOW_CMD_NEW, false); 902 error = ovs_flow_cmd_fill_info(flow,
888 ovs_unlock(); 903 ovs_header->dp_ifindex,
904 reply, info->snd_portid,
905 info->snd_seq, 0,
906 OVS_FLOW_CMD_NEW);
907 BUG_ON(error < 0);
908 }
909 ovs_unlock();
889 910
890 if (reply) { 911 ovs_nla_free_flow_actions(old_acts);
891 if (!IS_ERR(reply)) 912 ovs_flow_free(new_flow, false);
892 ovs_notify(&dp_flow_genl_family, reply, info);
893 else
894 netlink_set_err(sock_net(skb->sk)->genl_sock, 0, 0,
895 PTR_ERR(reply));
896 } 913 }
914
915 if (reply)
916 ovs_notify(&dp_flow_genl_family, reply, info);
897 return 0; 917 return 0;
898 918
899err_flow_free:
900 ovs_flow_free(flow, false);
901err_unlock_ovs: 919err_unlock_ovs:
902 ovs_unlock(); 920 ovs_unlock();
903err_kfree: 921 kfree_skb(reply);
922err_kfree_acts:
904 kfree(acts); 923 kfree(acts);
924err_kfree_flow:
925 ovs_flow_free(new_flow, false);
905error: 926error:
906 return error; 927 return error;
907} 928}
@@ -915,7 +936,7 @@ static int ovs_flow_cmd_set(struct sk_buff *skb, struct genl_info *info)
915 struct sw_flow_mask mask; 936 struct sw_flow_mask mask;
916 struct sk_buff *reply = NULL; 937 struct sk_buff *reply = NULL;
917 struct datapath *dp; 938 struct datapath *dp;
918 struct sw_flow_actions *acts = NULL; 939 struct sw_flow_actions *old_acts = NULL, *acts = NULL;
919 struct sw_flow_match match; 940 struct sw_flow_match match;
920 int error; 941 int error;
921 942
@@ -942,56 +963,75 @@ static int ovs_flow_cmd_set(struct sk_buff *skb, struct genl_info *info)
942 &masked_key, 0, &acts); 963 &masked_key, 0, &acts);
943 if (error) { 964 if (error) {
944 OVS_NLERR("Flow actions may not be safe on all matching packets.\n"); 965 OVS_NLERR("Flow actions may not be safe on all matching packets.\n");
945 goto err_kfree; 966 goto err_kfree_acts;
967 }
968 }
969
970 /* Can allocate before locking if have acts. */
971 if (acts) {
972 reply = ovs_flow_cmd_alloc_info(acts, info, false);
973 if (IS_ERR(reply)) {
974 error = PTR_ERR(reply);
975 goto err_kfree_acts;
946 } 976 }
947 } 977 }
948 978
949 ovs_lock(); 979 ovs_lock();
950 dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex); 980 dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
951 error = -ENODEV; 981 if (unlikely(!dp)) {
952 if (!dp) 982 error = -ENODEV;
953 goto err_unlock_ovs; 983 goto err_unlock_ovs;
954 984 }
955 /* Check that the flow exists. */ 985 /* Check that the flow exists. */
956 flow = ovs_flow_tbl_lookup(&dp->table, &key); 986 flow = ovs_flow_tbl_lookup(&dp->table, &key);
957 error = -ENOENT; 987 if (unlikely(!flow)) {
958 if (!flow) 988 error = -ENOENT;
959 goto err_unlock_ovs; 989 goto err_unlock_ovs;
960 990 }
961 /* The unmasked key has to be the same for flow updates. */ 991 /* The unmasked key has to be the same for flow updates. */
962 error = -EEXIST; 992 if (unlikely(!ovs_flow_cmp_unmasked_key(flow, &match))) {
963 if (!ovs_flow_cmp_unmasked_key(flow, &match)) 993 error = -EEXIST;
964 goto err_unlock_ovs; 994 goto err_unlock_ovs;
965 995 }
966 /* Update actions, if present. */ 996 /* Update actions, if present. */
967 if (acts) { 997 if (likely(acts)) {
968 struct sw_flow_actions *old_acts;
969
970 old_acts = ovsl_dereference(flow->sf_acts); 998 old_acts = ovsl_dereference(flow->sf_acts);
971 rcu_assign_pointer(flow->sf_acts, acts); 999 rcu_assign_pointer(flow->sf_acts, acts);
972 ovs_nla_free_flow_actions(old_acts); 1000
1001 if (unlikely(reply)) {
1002 error = ovs_flow_cmd_fill_info(flow,
1003 ovs_header->dp_ifindex,
1004 reply, info->snd_portid,
1005 info->snd_seq, 0,
1006 OVS_FLOW_CMD_NEW);
1007 BUG_ON(error < 0);
1008 }
1009 } else {
1010 /* Could not alloc without acts before locking. */
1011 reply = ovs_flow_cmd_build_info(flow, ovs_header->dp_ifindex,
1012 info, OVS_FLOW_CMD_NEW, false);
1013 if (unlikely(IS_ERR(reply))) {
1014 error = PTR_ERR(reply);
1015 goto err_unlock_ovs;
1016 }
973 } 1017 }
974 1018
975 reply = ovs_flow_cmd_build_info(flow, ovs_header->dp_ifindex,
976 info, OVS_FLOW_CMD_NEW, false);
977 /* Clear stats. */ 1019 /* Clear stats. */
978 if (a[OVS_FLOW_ATTR_CLEAR]) 1020 if (a[OVS_FLOW_ATTR_CLEAR])
979 ovs_flow_stats_clear(flow); 1021 ovs_flow_stats_clear(flow);
980 ovs_unlock(); 1022 ovs_unlock();
981 1023
982 if (reply) { 1024 if (reply)
983 if (!IS_ERR(reply)) 1025 ovs_notify(&dp_flow_genl_family, reply, info);
984 ovs_notify(&dp_flow_genl_family, reply, info); 1026 if (old_acts)
985 else 1027 ovs_nla_free_flow_actions(old_acts);
986 genl_set_err(&dp_flow_genl_family, sock_net(skb->sk), 0,
987 0, PTR_ERR(reply));
988 }
989 1028
990 return 0; 1029 return 0;
991 1030
992err_unlock_ovs: 1031err_unlock_ovs:
993 ovs_unlock(); 1032 ovs_unlock();
994err_kfree: 1033 kfree_skb(reply);
1034err_kfree_acts:
995 kfree(acts); 1035 kfree(acts);
996error: 1036error:
997 return error; 1037 return error;