aboutsummaryrefslogtreecommitdiffstats
path: root/net/openvswitch
diff options
context:
space:
mode:
authorJarno Rajahalme <jrajahalme@nicira.com>2014-05-05 17:53:51 -0400
committerPravin B Shelar <pshelar@nicira.com>2014-05-22 19:27:36 -0400
commit37bdc87ba00dadd0156db77ba48224d042202435 (patch)
tree3cb42e5d6d99221c754fb727709d24c6ed7dc35a /net/openvswitch
parentaed067783e505bf66dcafa8647d08619eb5b1c55 (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.c160
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
795static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) 795static 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
899err_flow_free:
900 ovs_flow_free(flow, false);
901err_unlock_ovs:
902 ovs_unlock();
903err_kfree:
904 kfree(acts);
905error:
906 return error;
907}
893 908
894 old_acts = ovsl_dereference(flow->sf_acts); 909static 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
918err_flow_free:
919 ovs_flow_free(flow, false);
920err_unlock_ovs: 992err_unlock_ovs:
921 ovs_unlock(); 993 ovs_unlock();
922err_kfree: 994err_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