diff options
author | Jarno Rajahalme <jrajahalme@nicira.com> | 2014-05-05 17:53:51 -0400 |
---|---|---|
committer | Pravin B Shelar <pshelar@nicira.com> | 2014-05-22 19:27:36 -0400 |
commit | 37bdc87ba00dadd0156db77ba48224d042202435 (patch) | |
tree | 3cb42e5d6d99221c754fb727709d24c6ed7dc35a /net/openvswitch | |
parent | aed067783e505bf66dcafa8647d08619eb5b1c55 (diff) |
openvswitch: Split ovs_flow_cmd_new_or_set().
Following patch will be easier to reason about with separate
ovs_flow_cmd_new() and ovs_flow_cmd_set() functions.
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.c | 160 |
1 files changed, 116 insertions, 44 deletions
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c index f28beda8426f..22665a6144fc 100644 --- a/net/openvswitch/datapath.c +++ b/net/openvswitch/datapath.c | |||
@@ -792,16 +792,16 @@ static struct sk_buff *ovs_flow_cmd_build_info(const struct sw_flow *flow, | |||
792 | return skb; | 792 | return skb; |
793 | } | 793 | } |
794 | 794 | ||
795 | static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) | 795 | 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_key key, masked_key; |
800 | struct sw_flow *flow = NULL; | 800 | struct sw_flow *flow; |
801 | struct sw_flow_mask mask; | 801 | struct sw_flow_mask mask; |
802 | struct sk_buff *reply; | 802 | struct sk_buff *reply; |
803 | struct datapath *dp; | 803 | struct datapath *dp; |
804 | struct sw_flow_actions *acts = NULL; | 804 | struct sw_flow_actions *acts; |
805 | struct sw_flow_match match; | 805 | struct sw_flow_match match; |
806 | int error; | 806 | int error; |
807 | 807 | ||
@@ -817,23 +817,21 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) | |||
817 | goto error; | 817 | goto error; |
818 | 818 | ||
819 | /* Validate actions. */ | 819 | /* Validate actions. */ |
820 | if (a[OVS_FLOW_ATTR_ACTIONS]) { | 820 | error = -EINVAL; |
821 | acts = ovs_nla_alloc_flow_actions(nla_len(a[OVS_FLOW_ATTR_ACTIONS])); | 821 | if (!a[OVS_FLOW_ATTR_ACTIONS]) |
822 | error = PTR_ERR(acts); | 822 | goto error; |
823 | if (IS_ERR(acts)) | ||
824 | goto error; | ||
825 | 823 | ||
826 | ovs_flow_mask_key(&masked_key, &key, &mask); | 824 | acts = ovs_nla_alloc_flow_actions(nla_len(a[OVS_FLOW_ATTR_ACTIONS])); |
827 | error = ovs_nla_copy_actions(a[OVS_FLOW_ATTR_ACTIONS], | 825 | error = PTR_ERR(acts); |
828 | &masked_key, 0, &acts); | 826 | if (IS_ERR(acts)) |
829 | if (error) { | ||
830 | OVS_NLERR("Flow actions may not be safe on all matching packets.\n"); | ||
831 | goto err_kfree; | ||
832 | } | ||
833 | } else if (info->genlhdr->cmd == OVS_FLOW_CMD_NEW) { | ||
834 | /* OVS_FLOW_CMD_NEW must have actions. */ | ||
835 | error = -EINVAL; | ||
836 | goto error; | 827 | goto error; |
828 | |||
829 | ovs_flow_mask_key(&masked_key, &key, &mask); | ||
830 | error = ovs_nla_copy_actions(a[OVS_FLOW_ATTR_ACTIONS], | ||
831 | &masked_key, 0, &acts); | ||
832 | if (error) { | ||
833 | OVS_NLERR("Flow actions may not be safe on all matching packets.\n"); | ||
834 | goto err_kfree; | ||
837 | } | 835 | } |
838 | 836 | ||
839 | ovs_lock(); | 837 | ovs_lock(); |
@@ -845,11 +843,6 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) | |||
845 | /* Check if this is a duplicate flow */ | 843 | /* Check if this is a duplicate flow */ |
846 | flow = ovs_flow_tbl_lookup(&dp->table, &key); | 844 | flow = ovs_flow_tbl_lookup(&dp->table, &key); |
847 | if (!flow) { | 845 | if (!flow) { |
848 | /* Bail out if we're not allowed to create a new flow. */ | ||
849 | error = -ENOENT; | ||
850 | if (info->genlhdr->cmd == OVS_FLOW_CMD_SET) | ||
851 | goto err_unlock_ovs; | ||
852 | |||
853 | /* Allocate flow. */ | 846 | /* Allocate flow. */ |
854 | flow = ovs_flow_alloc(); | 847 | flow = ovs_flow_alloc(); |
855 | if (IS_ERR(flow)) { | 848 | if (IS_ERR(flow)) { |
@@ -867,11 +860,9 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) | |||
867 | acts = NULL; | 860 | acts = NULL; |
868 | goto err_flow_free; | 861 | goto err_flow_free; |
869 | } | 862 | } |
870 | |||
871 | reply = ovs_flow_cmd_build_info(flow, ovs_header->dp_ifindex, | ||
872 | info, OVS_FLOW_CMD_NEW, false); | ||
873 | } else { | 863 | } else { |
874 | /* We found a matching flow. */ | 864 | struct sw_flow_actions *old_acts; |
865 | |||
875 | /* Bail out if we're not allowed to modify an existing flow. | 866 | /* Bail out if we're not allowed to modify an existing flow. |
876 | * We accept NLM_F_CREATE in place of the intended NLM_F_EXCL | 867 | * We accept NLM_F_CREATE in place of the intended NLM_F_EXCL |
877 | * because Generic Netlink treats the latter as a dump | 868 | * because Generic Netlink treats the latter as a dump |
@@ -879,30 +870,113 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) | |||
879 | * gets fixed. | 870 | * gets fixed. |
880 | */ | 871 | */ |
881 | error = -EEXIST; | 872 | error = -EEXIST; |
882 | if (info->genlhdr->cmd == OVS_FLOW_CMD_NEW && | 873 | if (info->nlhdr->nlmsg_flags & (NLM_F_CREATE | NLM_F_EXCL)) |
883 | info->nlhdr->nlmsg_flags & (NLM_F_CREATE | NLM_F_EXCL)) | ||
884 | goto err_unlock_ovs; | 874 | goto err_unlock_ovs; |
885 | 875 | ||
886 | /* The unmasked key has to be the same for flow updates. */ | 876 | /* The unmasked key has to be the same for flow updates. */ |
887 | if (!ovs_flow_cmp_unmasked_key(flow, &match)) | 877 | if (!ovs_flow_cmp_unmasked_key(flow, &match)) |
888 | goto err_unlock_ovs; | 878 | goto err_unlock_ovs; |
889 | 879 | ||
890 | /* Update actions, if present. */ | 880 | /* Update actions. */ |
891 | if (acts) { | 881 | old_acts = ovsl_dereference(flow->sf_acts); |
892 | struct sw_flow_actions *old_acts; | 882 | rcu_assign_pointer(flow->sf_acts, acts); |
883 | ovs_nla_free_flow_actions(old_acts); | ||
884 | } | ||
885 | |||
886 | reply = ovs_flow_cmd_build_info(flow, ovs_header->dp_ifindex, | ||
887 | info, OVS_FLOW_CMD_NEW, false); | ||
888 | ovs_unlock(); | ||
889 | |||
890 | if (reply) { | ||
891 | if (!IS_ERR(reply)) | ||
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 | } | ||
897 | return 0; | ||
898 | |||
899 | err_flow_free: | ||
900 | ovs_flow_free(flow, false); | ||
901 | err_unlock_ovs: | ||
902 | ovs_unlock(); | ||
903 | err_kfree: | ||
904 | kfree(acts); | ||
905 | error: | ||
906 | return error; | ||
907 | } | ||
893 | 908 | ||
894 | old_acts = ovsl_dereference(flow->sf_acts); | 909 | static int ovs_flow_cmd_set(struct sk_buff *skb, struct genl_info *info) |
895 | rcu_assign_pointer(flow->sf_acts, acts); | 910 | { |
896 | ovs_nla_free_flow_actions(old_acts); | 911 | struct nlattr **a = info->attrs; |
912 | struct ovs_header *ovs_header = info->userhdr; | ||
913 | struct sw_flow_key key, masked_key; | ||
914 | struct sw_flow *flow; | ||
915 | struct sw_flow_mask mask; | ||
916 | struct sk_buff *reply = NULL; | ||
917 | struct datapath *dp; | ||
918 | struct sw_flow_actions *acts = NULL; | ||
919 | struct sw_flow_match match; | ||
920 | int error; | ||
921 | |||
922 | /* Extract key. */ | ||
923 | error = -EINVAL; | ||
924 | if (!a[OVS_FLOW_ATTR_KEY]) | ||
925 | goto error; | ||
926 | |||
927 | ovs_match_init(&match, &key, &mask); | ||
928 | error = ovs_nla_get_match(&match, | ||
929 | a[OVS_FLOW_ATTR_KEY], a[OVS_FLOW_ATTR_MASK]); | ||
930 | if (error) | ||
931 | goto error; | ||
932 | |||
933 | /* Validate actions. */ | ||
934 | if (a[OVS_FLOW_ATTR_ACTIONS]) { | ||
935 | acts = ovs_nla_alloc_flow_actions(nla_len(a[OVS_FLOW_ATTR_ACTIONS])); | ||
936 | error = PTR_ERR(acts); | ||
937 | if (IS_ERR(acts)) | ||
938 | goto error; | ||
939 | |||
940 | ovs_flow_mask_key(&masked_key, &key, &mask); | ||
941 | error = ovs_nla_copy_actions(a[OVS_FLOW_ATTR_ACTIONS], | ||
942 | &masked_key, 0, &acts); | ||
943 | if (error) { | ||
944 | OVS_NLERR("Flow actions may not be safe on all matching packets.\n"); | ||
945 | goto err_kfree; | ||
897 | } | 946 | } |
947 | } | ||
898 | 948 | ||
899 | reply = ovs_flow_cmd_build_info(flow, ovs_header->dp_ifindex, | 949 | ovs_lock(); |
900 | info, OVS_FLOW_CMD_NEW, false); | 950 | dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex); |
951 | error = -ENODEV; | ||
952 | if (!dp) | ||
953 | goto err_unlock_ovs; | ||
954 | |||
955 | /* Check that the flow exists. */ | ||
956 | flow = ovs_flow_tbl_lookup(&dp->table, &key); | ||
957 | error = -ENOENT; | ||
958 | if (!flow) | ||
959 | goto err_unlock_ovs; | ||
960 | |||
961 | /* The unmasked key has to be the same for flow updates. */ | ||
962 | error = -EEXIST; | ||
963 | if (!ovs_flow_cmp_unmasked_key(flow, &match)) | ||
964 | goto err_unlock_ovs; | ||
901 | 965 | ||
902 | /* Clear stats. */ | 966 | /* Update actions, if present. */ |
903 | if (a[OVS_FLOW_ATTR_CLEAR]) | 967 | if (acts) { |
904 | ovs_flow_stats_clear(flow); | 968 | struct sw_flow_actions *old_acts; |
969 | |||
970 | old_acts = ovsl_dereference(flow->sf_acts); | ||
971 | rcu_assign_pointer(flow->sf_acts, acts); | ||
972 | ovs_nla_free_flow_actions(old_acts); | ||
905 | } | 973 | } |
974 | |||
975 | reply = ovs_flow_cmd_build_info(flow, ovs_header->dp_ifindex, | ||
976 | info, OVS_FLOW_CMD_NEW, false); | ||
977 | /* Clear stats. */ | ||
978 | if (a[OVS_FLOW_ATTR_CLEAR]) | ||
979 | ovs_flow_stats_clear(flow); | ||
906 | ovs_unlock(); | 980 | ovs_unlock(); |
907 | 981 | ||
908 | if (reply) { | 982 | if (reply) { |
@@ -915,8 +989,6 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) | |||
915 | 989 | ||
916 | return 0; | 990 | return 0; |
917 | 991 | ||
918 | err_flow_free: | ||
919 | ovs_flow_free(flow, false); | ||
920 | err_unlock_ovs: | 992 | err_unlock_ovs: |
921 | ovs_unlock(); | 993 | ovs_unlock(); |
922 | err_kfree: | 994 | err_kfree: |
@@ -1078,7 +1150,7 @@ static const struct genl_ops dp_flow_genl_ops[] = { | |||
1078 | { .cmd = OVS_FLOW_CMD_NEW, | 1150 | { .cmd = OVS_FLOW_CMD_NEW, |
1079 | .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ | 1151 | .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ |
1080 | .policy = flow_policy, | 1152 | .policy = flow_policy, |
1081 | .doit = ovs_flow_cmd_new_or_set | 1153 | .doit = ovs_flow_cmd_new |
1082 | }, | 1154 | }, |
1083 | { .cmd = OVS_FLOW_CMD_DEL, | 1155 | { .cmd = OVS_FLOW_CMD_DEL, |
1084 | .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ | 1156 | .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ |
@@ -1094,7 +1166,7 @@ static const struct genl_ops dp_flow_genl_ops[] = { | |||
1094 | { .cmd = OVS_FLOW_CMD_SET, | 1166 | { .cmd = OVS_FLOW_CMD_SET, |
1095 | .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ | 1167 | .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ |
1096 | .policy = flow_policy, | 1168 | .policy = flow_policy, |
1097 | .doit = ovs_flow_cmd_new_or_set, | 1169 | .doit = ovs_flow_cmd_set, |
1098 | }, | 1170 | }, |
1099 | }; | 1171 | }; |
1100 | 1172 | ||