diff options
Diffstat (limited to 'net/openvswitch/datapath.c')
-rw-r--r-- | net/openvswitch/datapath.c | 243 |
1 files changed, 162 insertions, 81 deletions
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c index 332b5a031739..ae5e77cdc0ca 100644 --- a/net/openvswitch/datapath.c +++ b/net/openvswitch/datapath.c | |||
@@ -65,6 +65,8 @@ static struct genl_family dp_packet_genl_family; | |||
65 | static struct genl_family dp_flow_genl_family; | 65 | static struct genl_family dp_flow_genl_family; |
66 | static struct genl_family dp_datapath_genl_family; | 66 | static struct genl_family dp_datapath_genl_family; |
67 | 67 | ||
68 | static const struct nla_policy flow_policy[]; | ||
69 | |||
68 | static const struct genl_multicast_group ovs_dp_flow_multicast_group = { | 70 | static const struct genl_multicast_group ovs_dp_flow_multicast_group = { |
69 | .name = OVS_FLOW_MCGROUP, | 71 | .name = OVS_FLOW_MCGROUP, |
70 | }; | 72 | }; |
@@ -83,8 +85,7 @@ static bool ovs_must_notify(struct genl_family *family, struct genl_info *info, | |||
83 | unsigned int group) | 85 | unsigned int group) |
84 | { | 86 | { |
85 | return info->nlhdr->nlmsg_flags & NLM_F_ECHO || | 87 | return info->nlhdr->nlmsg_flags & NLM_F_ECHO || |
86 | genl_has_listeners(family, genl_info_net(info)->genl_sock, | 88 | genl_has_listeners(family, genl_info_net(info), group); |
87 | group); | ||
88 | } | 89 | } |
89 | 90 | ||
90 | static void ovs_notify(struct genl_family *family, | 91 | static void ovs_notify(struct genl_family *family, |
@@ -420,7 +421,7 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb, | |||
420 | if (!dp_ifindex) | 421 | if (!dp_ifindex) |
421 | return -ENODEV; | 422 | return -ENODEV; |
422 | 423 | ||
423 | if (vlan_tx_tag_present(skb)) { | 424 | if (skb_vlan_tag_present(skb)) { |
424 | nskb = skb_clone(skb, GFP_ATOMIC); | 425 | nskb = skb_clone(skb, GFP_ATOMIC); |
425 | if (!nskb) | 426 | if (!nskb) |
426 | return -ENOMEM; | 427 | return -ENOMEM; |
@@ -462,10 +463,8 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb, | |||
462 | 0, upcall_info->cmd); | 463 | 0, upcall_info->cmd); |
463 | upcall->dp_ifindex = dp_ifindex; | 464 | upcall->dp_ifindex = dp_ifindex; |
464 | 465 | ||
465 | nla = nla_nest_start(user_skb, OVS_PACKET_ATTR_KEY); | 466 | err = ovs_nla_put_key(key, key, OVS_PACKET_ATTR_KEY, false, user_skb); |
466 | err = ovs_nla_put_flow(key, key, user_skb); | ||
467 | BUG_ON(err); | 467 | BUG_ON(err); |
468 | nla_nest_end(user_skb, nla); | ||
469 | 468 | ||
470 | if (upcall_info->userdata) | 469 | if (upcall_info->userdata) |
471 | __nla_put(user_skb, OVS_PACKET_ATTR_USERDATA, | 470 | __nla_put(user_skb, OVS_PACKET_ATTR_USERDATA, |
@@ -525,7 +524,7 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info) | |||
525 | struct vport *input_vport; | 524 | struct vport *input_vport; |
526 | int len; | 525 | int len; |
527 | int err; | 526 | int err; |
528 | bool log = !a[OVS_FLOW_ATTR_PROBE]; | 527 | bool log = !a[OVS_PACKET_ATTR_PROBE]; |
529 | 528 | ||
530 | err = -EINVAL; | 529 | err = -EINVAL; |
531 | if (!a[OVS_PACKET_ATTR_PACKET] || !a[OVS_PACKET_ATTR_KEY] || | 530 | if (!a[OVS_PACKET_ATTR_PACKET] || !a[OVS_PACKET_ATTR_KEY] || |
@@ -611,6 +610,7 @@ static const struct nla_policy packet_policy[OVS_PACKET_ATTR_MAX + 1] = { | |||
611 | [OVS_PACKET_ATTR_PACKET] = { .len = ETH_HLEN }, | 610 | [OVS_PACKET_ATTR_PACKET] = { .len = ETH_HLEN }, |
612 | [OVS_PACKET_ATTR_KEY] = { .type = NLA_NESTED }, | 611 | [OVS_PACKET_ATTR_KEY] = { .type = NLA_NESTED }, |
613 | [OVS_PACKET_ATTR_ACTIONS] = { .type = NLA_NESTED }, | 612 | [OVS_PACKET_ATTR_ACTIONS] = { .type = NLA_NESTED }, |
613 | [OVS_PACKET_ATTR_PROBE] = { .type = NLA_FLAG }, | ||
614 | }; | 614 | }; |
615 | 615 | ||
616 | static const struct genl_ops dp_packet_genl_ops[] = { | 616 | static const struct genl_ops dp_packet_genl_ops[] = { |
@@ -664,46 +664,48 @@ static void get_dp_stats(const struct datapath *dp, struct ovs_dp_stats *stats, | |||
664 | } | 664 | } |
665 | } | 665 | } |
666 | 666 | ||
667 | static size_t ovs_flow_cmd_msg_size(const struct sw_flow_actions *acts) | 667 | static bool should_fill_key(const struct sw_flow_id *sfid, uint32_t ufid_flags) |
668 | { | 668 | { |
669 | return NLMSG_ALIGN(sizeof(struct ovs_header)) | 669 | return ovs_identifier_is_ufid(sfid) && |
670 | + nla_total_size(ovs_key_attr_size()) /* OVS_FLOW_ATTR_KEY */ | 670 | !(ufid_flags & OVS_UFID_F_OMIT_KEY); |
671 | + nla_total_size(ovs_key_attr_size()) /* OVS_FLOW_ATTR_MASK */ | ||
672 | + nla_total_size(sizeof(struct ovs_flow_stats)) /* OVS_FLOW_ATTR_STATS */ | ||
673 | + nla_total_size(1) /* OVS_FLOW_ATTR_TCP_FLAGS */ | ||
674 | + nla_total_size(8) /* OVS_FLOW_ATTR_USED */ | ||
675 | + nla_total_size(acts->actions_len); /* OVS_FLOW_ATTR_ACTIONS */ | ||
676 | } | 671 | } |
677 | 672 | ||
678 | /* Called with ovs_mutex or RCU read lock. */ | 673 | static bool should_fill_mask(uint32_t ufid_flags) |
679 | static int ovs_flow_cmd_fill_match(const struct sw_flow *flow, | ||
680 | struct sk_buff *skb) | ||
681 | { | 674 | { |
682 | struct nlattr *nla; | 675 | return !(ufid_flags & OVS_UFID_F_OMIT_MASK); |
683 | int err; | 676 | } |
684 | 677 | ||
685 | /* Fill flow key. */ | 678 | static bool should_fill_actions(uint32_t ufid_flags) |
686 | nla = nla_nest_start(skb, OVS_FLOW_ATTR_KEY); | 679 | { |
687 | if (!nla) | 680 | return !(ufid_flags & OVS_UFID_F_OMIT_ACTIONS); |
688 | return -EMSGSIZE; | 681 | } |
689 | 682 | ||
690 | err = ovs_nla_put_flow(&flow->unmasked_key, &flow->unmasked_key, skb); | 683 | static size_t ovs_flow_cmd_msg_size(const struct sw_flow_actions *acts, |
691 | if (err) | 684 | const struct sw_flow_id *sfid, |
692 | return err; | 685 | uint32_t ufid_flags) |
686 | { | ||
687 | size_t len = NLMSG_ALIGN(sizeof(struct ovs_header)); | ||
693 | 688 | ||
694 | nla_nest_end(skb, nla); | 689 | /* OVS_FLOW_ATTR_UFID */ |
690 | if (sfid && ovs_identifier_is_ufid(sfid)) | ||
691 | len += nla_total_size(sfid->ufid_len); | ||
695 | 692 | ||
696 | /* Fill flow mask. */ | 693 | /* OVS_FLOW_ATTR_KEY */ |
697 | nla = nla_nest_start(skb, OVS_FLOW_ATTR_MASK); | 694 | if (!sfid || should_fill_key(sfid, ufid_flags)) |
698 | if (!nla) | 695 | len += nla_total_size(ovs_key_attr_size()); |
699 | return -EMSGSIZE; | ||
700 | 696 | ||
701 | err = ovs_nla_put_flow(&flow->key, &flow->mask->key, skb); | 697 | /* OVS_FLOW_ATTR_MASK */ |
702 | if (err) | 698 | if (should_fill_mask(ufid_flags)) |
703 | return err; | 699 | len += nla_total_size(ovs_key_attr_size()); |
704 | 700 | ||
705 | nla_nest_end(skb, nla); | 701 | /* OVS_FLOW_ATTR_ACTIONS */ |
706 | return 0; | 702 | if (should_fill_actions(ufid_flags)) |
703 | len += nla_total_size(acts->actions_len); | ||
704 | |||
705 | return len | ||
706 | + nla_total_size(sizeof(struct ovs_flow_stats)) /* OVS_FLOW_ATTR_STATS */ | ||
707 | + nla_total_size(1) /* OVS_FLOW_ATTR_TCP_FLAGS */ | ||
708 | + nla_total_size(8); /* OVS_FLOW_ATTR_USED */ | ||
707 | } | 709 | } |
708 | 710 | ||
709 | /* Called with ovs_mutex or RCU read lock. */ | 711 | /* Called with ovs_mutex or RCU read lock. */ |
@@ -774,7 +776,7 @@ static int ovs_flow_cmd_fill_actions(const struct sw_flow *flow, | |||
774 | /* Called with ovs_mutex or RCU read lock. */ | 776 | /* Called with ovs_mutex or RCU read lock. */ |
775 | static int ovs_flow_cmd_fill_info(const struct sw_flow *flow, int dp_ifindex, | 777 | static int ovs_flow_cmd_fill_info(const struct sw_flow *flow, int dp_ifindex, |
776 | struct sk_buff *skb, u32 portid, | 778 | struct sk_buff *skb, u32 portid, |
777 | u32 seq, u32 flags, u8 cmd) | 779 | u32 seq, u32 flags, u8 cmd, u32 ufid_flags) |
778 | { | 780 | { |
779 | const int skb_orig_len = skb->len; | 781 | const int skb_orig_len = skb->len; |
780 | struct ovs_header *ovs_header; | 782 | struct ovs_header *ovs_header; |
@@ -787,19 +789,34 @@ static int ovs_flow_cmd_fill_info(const struct sw_flow *flow, int dp_ifindex, | |||
787 | 789 | ||
788 | ovs_header->dp_ifindex = dp_ifindex; | 790 | ovs_header->dp_ifindex = dp_ifindex; |
789 | 791 | ||
790 | err = ovs_flow_cmd_fill_match(flow, skb); | 792 | err = ovs_nla_put_identifier(flow, skb); |
791 | if (err) | 793 | if (err) |
792 | goto error; | 794 | goto error; |
793 | 795 | ||
796 | if (should_fill_key(&flow->id, ufid_flags)) { | ||
797 | err = ovs_nla_put_masked_key(flow, skb); | ||
798 | if (err) | ||
799 | goto error; | ||
800 | } | ||
801 | |||
802 | if (should_fill_mask(ufid_flags)) { | ||
803 | err = ovs_nla_put_mask(flow, skb); | ||
804 | if (err) | ||
805 | goto error; | ||
806 | } | ||
807 | |||
794 | err = ovs_flow_cmd_fill_stats(flow, skb); | 808 | err = ovs_flow_cmd_fill_stats(flow, skb); |
795 | if (err) | 809 | if (err) |
796 | goto error; | 810 | goto error; |
797 | 811 | ||
798 | err = ovs_flow_cmd_fill_actions(flow, skb, skb_orig_len); | 812 | if (should_fill_actions(ufid_flags)) { |
799 | if (err) | 813 | err = ovs_flow_cmd_fill_actions(flow, skb, skb_orig_len); |
800 | goto error; | 814 | if (err) |
815 | goto error; | ||
816 | } | ||
801 | 817 | ||
802 | return genlmsg_end(skb, ovs_header); | 818 | genlmsg_end(skb, ovs_header); |
819 | return 0; | ||
803 | 820 | ||
804 | error: | 821 | error: |
805 | genlmsg_cancel(skb, ovs_header); | 822 | genlmsg_cancel(skb, ovs_header); |
@@ -808,15 +825,19 @@ error: | |||
808 | 825 | ||
809 | /* May not be called with RCU read lock. */ | 826 | /* May not be called with RCU read lock. */ |
810 | static struct sk_buff *ovs_flow_cmd_alloc_info(const struct sw_flow_actions *acts, | 827 | static struct sk_buff *ovs_flow_cmd_alloc_info(const struct sw_flow_actions *acts, |
828 | const struct sw_flow_id *sfid, | ||
811 | struct genl_info *info, | 829 | struct genl_info *info, |
812 | bool always) | 830 | bool always, |
831 | uint32_t ufid_flags) | ||
813 | { | 832 | { |
814 | struct sk_buff *skb; | 833 | struct sk_buff *skb; |
834 | size_t len; | ||
815 | 835 | ||
816 | if (!always && !ovs_must_notify(&dp_flow_genl_family, info, 0)) | 836 | if (!always && !ovs_must_notify(&dp_flow_genl_family, info, 0)) |
817 | return NULL; | 837 | return NULL; |
818 | 838 | ||
819 | skb = genlmsg_new_unicast(ovs_flow_cmd_msg_size(acts), info, GFP_KERNEL); | 839 | len = ovs_flow_cmd_msg_size(acts, sfid, ufid_flags); |
840 | skb = genlmsg_new_unicast(len, info, GFP_KERNEL); | ||
820 | if (!skb) | 841 | if (!skb) |
821 | return ERR_PTR(-ENOMEM); | 842 | return ERR_PTR(-ENOMEM); |
822 | 843 | ||
@@ -827,19 +848,19 @@ static struct sk_buff *ovs_flow_cmd_alloc_info(const struct sw_flow_actions *act | |||
827 | static struct sk_buff *ovs_flow_cmd_build_info(const struct sw_flow *flow, | 848 | static struct sk_buff *ovs_flow_cmd_build_info(const struct sw_flow *flow, |
828 | int dp_ifindex, | 849 | int dp_ifindex, |
829 | struct genl_info *info, u8 cmd, | 850 | struct genl_info *info, u8 cmd, |
830 | bool always) | 851 | bool always, u32 ufid_flags) |
831 | { | 852 | { |
832 | struct sk_buff *skb; | 853 | struct sk_buff *skb; |
833 | int retval; | 854 | int retval; |
834 | 855 | ||
835 | skb = ovs_flow_cmd_alloc_info(ovsl_dereference(flow->sf_acts), info, | 856 | skb = ovs_flow_cmd_alloc_info(ovsl_dereference(flow->sf_acts), |
836 | always); | 857 | &flow->id, info, always, ufid_flags); |
837 | if (IS_ERR_OR_NULL(skb)) | 858 | if (IS_ERR_OR_NULL(skb)) |
838 | return skb; | 859 | return skb; |
839 | 860 | ||
840 | retval = ovs_flow_cmd_fill_info(flow, dp_ifindex, skb, | 861 | retval = ovs_flow_cmd_fill_info(flow, dp_ifindex, skb, |
841 | info->snd_portid, info->snd_seq, 0, | 862 | info->snd_portid, info->snd_seq, 0, |
842 | cmd); | 863 | cmd, ufid_flags); |
843 | BUG_ON(retval < 0); | 864 | BUG_ON(retval < 0); |
844 | return skb; | 865 | return skb; |
845 | } | 866 | } |
@@ -848,12 +869,14 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info) | |||
848 | { | 869 | { |
849 | struct nlattr **a = info->attrs; | 870 | struct nlattr **a = info->attrs; |
850 | struct ovs_header *ovs_header = info->userhdr; | 871 | struct ovs_header *ovs_header = info->userhdr; |
851 | struct sw_flow *flow, *new_flow; | 872 | struct sw_flow *flow = NULL, *new_flow; |
852 | struct sw_flow_mask mask; | 873 | struct sw_flow_mask mask; |
853 | struct sk_buff *reply; | 874 | struct sk_buff *reply; |
854 | struct datapath *dp; | 875 | struct datapath *dp; |
876 | struct sw_flow_key key; | ||
855 | struct sw_flow_actions *acts; | 877 | struct sw_flow_actions *acts; |
856 | struct sw_flow_match match; | 878 | struct sw_flow_match match; |
879 | u32 ufid_flags = ovs_nla_get_ufid_flags(a[OVS_FLOW_ATTR_UFID_FLAGS]); | ||
857 | int error; | 880 | int error; |
858 | bool log = !a[OVS_FLOW_ATTR_PROBE]; | 881 | bool log = !a[OVS_FLOW_ATTR_PROBE]; |
859 | 882 | ||
@@ -878,13 +901,19 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info) | |||
878 | } | 901 | } |
879 | 902 | ||
880 | /* Extract key. */ | 903 | /* Extract key. */ |
881 | ovs_match_init(&match, &new_flow->unmasked_key, &mask); | 904 | ovs_match_init(&match, &key, &mask); |
882 | error = ovs_nla_get_match(&match, a[OVS_FLOW_ATTR_KEY], | 905 | error = ovs_nla_get_match(&match, a[OVS_FLOW_ATTR_KEY], |
883 | a[OVS_FLOW_ATTR_MASK], log); | 906 | a[OVS_FLOW_ATTR_MASK], log); |
884 | if (error) | 907 | if (error) |
885 | goto err_kfree_flow; | 908 | goto err_kfree_flow; |
886 | 909 | ||
887 | ovs_flow_mask_key(&new_flow->key, &new_flow->unmasked_key, &mask); | 910 | ovs_flow_mask_key(&new_flow->key, &key, &mask); |
911 | |||
912 | /* Extract flow identifier. */ | ||
913 | error = ovs_nla_get_identifier(&new_flow->id, a[OVS_FLOW_ATTR_UFID], | ||
914 | &key, log); | ||
915 | if (error) | ||
916 | goto err_kfree_flow; | ||
888 | 917 | ||
889 | /* Validate actions. */ | 918 | /* Validate actions. */ |
890 | error = ovs_nla_copy_actions(a[OVS_FLOW_ATTR_ACTIONS], &new_flow->key, | 919 | error = ovs_nla_copy_actions(a[OVS_FLOW_ATTR_ACTIONS], &new_flow->key, |
@@ -894,7 +923,8 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info) | |||
894 | goto err_kfree_flow; | 923 | goto err_kfree_flow; |
895 | } | 924 | } |
896 | 925 | ||
897 | reply = ovs_flow_cmd_alloc_info(acts, info, false); | 926 | reply = ovs_flow_cmd_alloc_info(acts, &new_flow->id, info, false, |
927 | ufid_flags); | ||
898 | if (IS_ERR(reply)) { | 928 | if (IS_ERR(reply)) { |
899 | error = PTR_ERR(reply); | 929 | error = PTR_ERR(reply); |
900 | goto err_kfree_acts; | 930 | goto err_kfree_acts; |
@@ -906,8 +936,12 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info) | |||
906 | error = -ENODEV; | 936 | error = -ENODEV; |
907 | goto err_unlock_ovs; | 937 | goto err_unlock_ovs; |
908 | } | 938 | } |
939 | |||
909 | /* Check if this is a duplicate flow */ | 940 | /* Check if this is a duplicate flow */ |
910 | flow = ovs_flow_tbl_lookup(&dp->table, &new_flow->unmasked_key); | 941 | if (ovs_identifier_is_ufid(&new_flow->id)) |
942 | flow = ovs_flow_tbl_lookup_ufid(&dp->table, &new_flow->id); | ||
943 | if (!flow) | ||
944 | flow = ovs_flow_tbl_lookup(&dp->table, &key); | ||
911 | if (likely(!flow)) { | 945 | if (likely(!flow)) { |
912 | rcu_assign_pointer(new_flow->sf_acts, acts); | 946 | rcu_assign_pointer(new_flow->sf_acts, acts); |
913 | 947 | ||
@@ -923,7 +957,8 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info) | |||
923 | ovs_header->dp_ifindex, | 957 | ovs_header->dp_ifindex, |
924 | reply, info->snd_portid, | 958 | reply, info->snd_portid, |
925 | info->snd_seq, 0, | 959 | info->snd_seq, 0, |
926 | OVS_FLOW_CMD_NEW); | 960 | OVS_FLOW_CMD_NEW, |
961 | ufid_flags); | ||
927 | BUG_ON(error < 0); | 962 | BUG_ON(error < 0); |
928 | } | 963 | } |
929 | ovs_unlock(); | 964 | ovs_unlock(); |
@@ -941,10 +976,15 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info) | |||
941 | error = -EEXIST; | 976 | error = -EEXIST; |
942 | goto err_unlock_ovs; | 977 | goto err_unlock_ovs; |
943 | } | 978 | } |
944 | /* The unmasked key has to be the same for flow updates. */ | 979 | /* The flow identifier has to be the same for flow updates. |
945 | if (unlikely(!ovs_flow_cmp_unmasked_key(flow, &match))) { | 980 | * Look for any overlapping flow. |
946 | /* Look for any overlapping flow. */ | 981 | */ |
947 | flow = ovs_flow_tbl_lookup_exact(&dp->table, &match); | 982 | if (unlikely(!ovs_flow_cmp(flow, &match))) { |
983 | if (ovs_identifier_is_key(&flow->id)) | ||
984 | flow = ovs_flow_tbl_lookup_exact(&dp->table, | ||
985 | &match); | ||
986 | else /* UFID matches but key is different */ | ||
987 | flow = NULL; | ||
948 | if (!flow) { | 988 | if (!flow) { |
949 | error = -ENOENT; | 989 | error = -ENOENT; |
950 | goto err_unlock_ovs; | 990 | goto err_unlock_ovs; |
@@ -959,7 +999,8 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info) | |||
959 | ovs_header->dp_ifindex, | 999 | ovs_header->dp_ifindex, |
960 | reply, info->snd_portid, | 1000 | reply, info->snd_portid, |
961 | info->snd_seq, 0, | 1001 | info->snd_seq, 0, |
962 | OVS_FLOW_CMD_NEW); | 1002 | OVS_FLOW_CMD_NEW, |
1003 | ufid_flags); | ||
963 | BUG_ON(error < 0); | 1004 | BUG_ON(error < 0); |
964 | } | 1005 | } |
965 | ovs_unlock(); | 1006 | ovs_unlock(); |
@@ -1015,8 +1056,11 @@ static int ovs_flow_cmd_set(struct sk_buff *skb, struct genl_info *info) | |||
1015 | struct datapath *dp; | 1056 | struct datapath *dp; |
1016 | struct sw_flow_actions *old_acts = NULL, *acts = NULL; | 1057 | struct sw_flow_actions *old_acts = NULL, *acts = NULL; |
1017 | struct sw_flow_match match; | 1058 | struct sw_flow_match match; |
1059 | struct sw_flow_id sfid; | ||
1060 | u32 ufid_flags = ovs_nla_get_ufid_flags(a[OVS_FLOW_ATTR_UFID_FLAGS]); | ||
1018 | int error; | 1061 | int error; |
1019 | bool log = !a[OVS_FLOW_ATTR_PROBE]; | 1062 | bool log = !a[OVS_FLOW_ATTR_PROBE]; |
1063 | bool ufid_present; | ||
1020 | 1064 | ||
1021 | /* Extract key. */ | 1065 | /* Extract key. */ |
1022 | error = -EINVAL; | 1066 | error = -EINVAL; |
@@ -1025,6 +1069,7 @@ static int ovs_flow_cmd_set(struct sk_buff *skb, struct genl_info *info) | |||
1025 | goto error; | 1069 | goto error; |
1026 | } | 1070 | } |
1027 | 1071 | ||
1072 | ufid_present = ovs_nla_get_ufid(&sfid, a[OVS_FLOW_ATTR_UFID], log); | ||
1028 | ovs_match_init(&match, &key, &mask); | 1073 | ovs_match_init(&match, &key, &mask); |
1029 | error = ovs_nla_get_match(&match, a[OVS_FLOW_ATTR_KEY], | 1074 | error = ovs_nla_get_match(&match, a[OVS_FLOW_ATTR_KEY], |
1030 | a[OVS_FLOW_ATTR_MASK], log); | 1075 | a[OVS_FLOW_ATTR_MASK], log); |
@@ -1041,7 +1086,8 @@ static int ovs_flow_cmd_set(struct sk_buff *skb, struct genl_info *info) | |||
1041 | } | 1086 | } |
1042 | 1087 | ||
1043 | /* Can allocate before locking if have acts. */ | 1088 | /* Can allocate before locking if have acts. */ |
1044 | reply = ovs_flow_cmd_alloc_info(acts, info, false); | 1089 | reply = ovs_flow_cmd_alloc_info(acts, &sfid, info, false, |
1090 | ufid_flags); | ||
1045 | if (IS_ERR(reply)) { | 1091 | if (IS_ERR(reply)) { |
1046 | error = PTR_ERR(reply); | 1092 | error = PTR_ERR(reply); |
1047 | goto err_kfree_acts; | 1093 | goto err_kfree_acts; |
@@ -1055,7 +1101,10 @@ static int ovs_flow_cmd_set(struct sk_buff *skb, struct genl_info *info) | |||
1055 | goto err_unlock_ovs; | 1101 | goto err_unlock_ovs; |
1056 | } | 1102 | } |
1057 | /* Check that the flow exists. */ | 1103 | /* Check that the flow exists. */ |
1058 | flow = ovs_flow_tbl_lookup_exact(&dp->table, &match); | 1104 | if (ufid_present) |
1105 | flow = ovs_flow_tbl_lookup_ufid(&dp->table, &sfid); | ||
1106 | else | ||
1107 | flow = ovs_flow_tbl_lookup_exact(&dp->table, &match); | ||
1059 | if (unlikely(!flow)) { | 1108 | if (unlikely(!flow)) { |
1060 | error = -ENOENT; | 1109 | error = -ENOENT; |
1061 | goto err_unlock_ovs; | 1110 | goto err_unlock_ovs; |
@@ -1071,13 +1120,16 @@ static int ovs_flow_cmd_set(struct sk_buff *skb, struct genl_info *info) | |||
1071 | ovs_header->dp_ifindex, | 1120 | ovs_header->dp_ifindex, |
1072 | reply, info->snd_portid, | 1121 | reply, info->snd_portid, |
1073 | info->snd_seq, 0, | 1122 | info->snd_seq, 0, |
1074 | OVS_FLOW_CMD_NEW); | 1123 | OVS_FLOW_CMD_NEW, |
1124 | ufid_flags); | ||
1075 | BUG_ON(error < 0); | 1125 | BUG_ON(error < 0); |
1076 | } | 1126 | } |
1077 | } else { | 1127 | } else { |
1078 | /* Could not alloc without acts before locking. */ | 1128 | /* Could not alloc without acts before locking. */ |
1079 | reply = ovs_flow_cmd_build_info(flow, ovs_header->dp_ifindex, | 1129 | reply = ovs_flow_cmd_build_info(flow, ovs_header->dp_ifindex, |
1080 | info, OVS_FLOW_CMD_NEW, false); | 1130 | info, OVS_FLOW_CMD_NEW, false, |
1131 | ufid_flags); | ||
1132 | |||
1081 | if (unlikely(IS_ERR(reply))) { | 1133 | if (unlikely(IS_ERR(reply))) { |
1082 | error = PTR_ERR(reply); | 1134 | error = PTR_ERR(reply); |
1083 | goto err_unlock_ovs; | 1135 | goto err_unlock_ovs; |
@@ -1114,17 +1166,22 @@ static int ovs_flow_cmd_get(struct sk_buff *skb, struct genl_info *info) | |||
1114 | struct sw_flow *flow; | 1166 | struct sw_flow *flow; |
1115 | struct datapath *dp; | 1167 | struct datapath *dp; |
1116 | struct sw_flow_match match; | 1168 | struct sw_flow_match match; |
1117 | int err; | 1169 | struct sw_flow_id ufid; |
1170 | u32 ufid_flags = ovs_nla_get_ufid_flags(a[OVS_FLOW_ATTR_UFID_FLAGS]); | ||
1171 | int err = 0; | ||
1118 | bool log = !a[OVS_FLOW_ATTR_PROBE]; | 1172 | bool log = !a[OVS_FLOW_ATTR_PROBE]; |
1173 | bool ufid_present; | ||
1119 | 1174 | ||
1120 | if (!a[OVS_FLOW_ATTR_KEY]) { | 1175 | ufid_present = ovs_nla_get_ufid(&ufid, a[OVS_FLOW_ATTR_UFID], log); |
1176 | if (a[OVS_FLOW_ATTR_KEY]) { | ||
1177 | ovs_match_init(&match, &key, NULL); | ||
1178 | err = ovs_nla_get_match(&match, a[OVS_FLOW_ATTR_KEY], NULL, | ||
1179 | log); | ||
1180 | } else if (!ufid_present) { | ||
1121 | OVS_NLERR(log, | 1181 | OVS_NLERR(log, |
1122 | "Flow get message rejected, Key attribute missing."); | 1182 | "Flow get message rejected, Key attribute missing."); |
1123 | return -EINVAL; | 1183 | err = -EINVAL; |
1124 | } | 1184 | } |
1125 | |||
1126 | ovs_match_init(&match, &key, NULL); | ||
1127 | err = ovs_nla_get_match(&match, a[OVS_FLOW_ATTR_KEY], NULL, log); | ||
1128 | if (err) | 1185 | if (err) |
1129 | return err; | 1186 | return err; |
1130 | 1187 | ||
@@ -1135,14 +1192,17 @@ static int ovs_flow_cmd_get(struct sk_buff *skb, struct genl_info *info) | |||
1135 | goto unlock; | 1192 | goto unlock; |
1136 | } | 1193 | } |
1137 | 1194 | ||
1138 | flow = ovs_flow_tbl_lookup_exact(&dp->table, &match); | 1195 | if (ufid_present) |
1196 | flow = ovs_flow_tbl_lookup_ufid(&dp->table, &ufid); | ||
1197 | else | ||
1198 | flow = ovs_flow_tbl_lookup_exact(&dp->table, &match); | ||
1139 | if (!flow) { | 1199 | if (!flow) { |
1140 | err = -ENOENT; | 1200 | err = -ENOENT; |
1141 | goto unlock; | 1201 | goto unlock; |
1142 | } | 1202 | } |
1143 | 1203 | ||
1144 | reply = ovs_flow_cmd_build_info(flow, ovs_header->dp_ifindex, info, | 1204 | reply = ovs_flow_cmd_build_info(flow, ovs_header->dp_ifindex, info, |
1145 | OVS_FLOW_CMD_NEW, true); | 1205 | OVS_FLOW_CMD_NEW, true, ufid_flags); |
1146 | if (IS_ERR(reply)) { | 1206 | if (IS_ERR(reply)) { |
1147 | err = PTR_ERR(reply); | 1207 | err = PTR_ERR(reply); |
1148 | goto unlock; | 1208 | goto unlock; |
@@ -1161,13 +1221,17 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info) | |||
1161 | struct ovs_header *ovs_header = info->userhdr; | 1221 | struct ovs_header *ovs_header = info->userhdr; |
1162 | struct sw_flow_key key; | 1222 | struct sw_flow_key key; |
1163 | struct sk_buff *reply; | 1223 | struct sk_buff *reply; |
1164 | struct sw_flow *flow; | 1224 | struct sw_flow *flow = NULL; |
1165 | struct datapath *dp; | 1225 | struct datapath *dp; |
1166 | struct sw_flow_match match; | 1226 | struct sw_flow_match match; |
1227 | struct sw_flow_id ufid; | ||
1228 | u32 ufid_flags = ovs_nla_get_ufid_flags(a[OVS_FLOW_ATTR_UFID_FLAGS]); | ||
1167 | int err; | 1229 | int err; |
1168 | bool log = !a[OVS_FLOW_ATTR_PROBE]; | 1230 | bool log = !a[OVS_FLOW_ATTR_PROBE]; |
1231 | bool ufid_present; | ||
1169 | 1232 | ||
1170 | if (likely(a[OVS_FLOW_ATTR_KEY])) { | 1233 | ufid_present = ovs_nla_get_ufid(&ufid, a[OVS_FLOW_ATTR_UFID], log); |
1234 | if (a[OVS_FLOW_ATTR_KEY]) { | ||
1171 | ovs_match_init(&match, &key, NULL); | 1235 | ovs_match_init(&match, &key, NULL); |
1172 | err = ovs_nla_get_match(&match, a[OVS_FLOW_ATTR_KEY], NULL, | 1236 | err = ovs_nla_get_match(&match, a[OVS_FLOW_ATTR_KEY], NULL, |
1173 | log); | 1237 | log); |
@@ -1182,12 +1246,15 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info) | |||
1182 | goto unlock; | 1246 | goto unlock; |
1183 | } | 1247 | } |
1184 | 1248 | ||
1185 | if (unlikely(!a[OVS_FLOW_ATTR_KEY])) { | 1249 | if (unlikely(!a[OVS_FLOW_ATTR_KEY] && !ufid_present)) { |
1186 | err = ovs_flow_tbl_flush(&dp->table); | 1250 | err = ovs_flow_tbl_flush(&dp->table); |
1187 | goto unlock; | 1251 | goto unlock; |
1188 | } | 1252 | } |
1189 | 1253 | ||
1190 | flow = ovs_flow_tbl_lookup_exact(&dp->table, &match); | 1254 | if (ufid_present) |
1255 | flow = ovs_flow_tbl_lookup_ufid(&dp->table, &ufid); | ||
1256 | else | ||
1257 | flow = ovs_flow_tbl_lookup_exact(&dp->table, &match); | ||
1191 | if (unlikely(!flow)) { | 1258 | if (unlikely(!flow)) { |
1192 | err = -ENOENT; | 1259 | err = -ENOENT; |
1193 | goto unlock; | 1260 | goto unlock; |
@@ -1197,14 +1264,15 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info) | |||
1197 | ovs_unlock(); | 1264 | ovs_unlock(); |
1198 | 1265 | ||
1199 | reply = ovs_flow_cmd_alloc_info((const struct sw_flow_actions __force *) flow->sf_acts, | 1266 | reply = ovs_flow_cmd_alloc_info((const struct sw_flow_actions __force *) flow->sf_acts, |
1200 | info, false); | 1267 | &flow->id, info, false, ufid_flags); |
1201 | if (likely(reply)) { | 1268 | if (likely(reply)) { |
1202 | if (likely(!IS_ERR(reply))) { | 1269 | if (likely(!IS_ERR(reply))) { |
1203 | rcu_read_lock(); /*To keep RCU checker happy. */ | 1270 | rcu_read_lock(); /*To keep RCU checker happy. */ |
1204 | err = ovs_flow_cmd_fill_info(flow, ovs_header->dp_ifindex, | 1271 | err = ovs_flow_cmd_fill_info(flow, ovs_header->dp_ifindex, |
1205 | reply, info->snd_portid, | 1272 | reply, info->snd_portid, |
1206 | info->snd_seq, 0, | 1273 | info->snd_seq, 0, |
1207 | OVS_FLOW_CMD_DEL); | 1274 | OVS_FLOW_CMD_DEL, |
1275 | ufid_flags); | ||
1208 | rcu_read_unlock(); | 1276 | rcu_read_unlock(); |
1209 | BUG_ON(err < 0); | 1277 | BUG_ON(err < 0); |
1210 | 1278 | ||
@@ -1223,9 +1291,18 @@ unlock: | |||
1223 | 1291 | ||
1224 | static int ovs_flow_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb) | 1292 | static int ovs_flow_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb) |
1225 | { | 1293 | { |
1294 | struct nlattr *a[__OVS_FLOW_ATTR_MAX]; | ||
1226 | struct ovs_header *ovs_header = genlmsg_data(nlmsg_data(cb->nlh)); | 1295 | struct ovs_header *ovs_header = genlmsg_data(nlmsg_data(cb->nlh)); |
1227 | struct table_instance *ti; | 1296 | struct table_instance *ti; |
1228 | struct datapath *dp; | 1297 | struct datapath *dp; |
1298 | u32 ufid_flags; | ||
1299 | int err; | ||
1300 | |||
1301 | err = genlmsg_parse(cb->nlh, &dp_flow_genl_family, a, | ||
1302 | OVS_FLOW_ATTR_MAX, flow_policy); | ||
1303 | if (err) | ||
1304 | return err; | ||
1305 | ufid_flags = ovs_nla_get_ufid_flags(a[OVS_FLOW_ATTR_UFID_FLAGS]); | ||
1229 | 1306 | ||
1230 | rcu_read_lock(); | 1307 | rcu_read_lock(); |
1231 | dp = get_dp_rcu(sock_net(skb->sk), ovs_header->dp_ifindex); | 1308 | dp = get_dp_rcu(sock_net(skb->sk), ovs_header->dp_ifindex); |
@@ -1248,7 +1325,7 @@ static int ovs_flow_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb) | |||
1248 | if (ovs_flow_cmd_fill_info(flow, ovs_header->dp_ifindex, skb, | 1325 | if (ovs_flow_cmd_fill_info(flow, ovs_header->dp_ifindex, skb, |
1249 | NETLINK_CB(cb->skb).portid, | 1326 | NETLINK_CB(cb->skb).portid, |
1250 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | 1327 | cb->nlh->nlmsg_seq, NLM_F_MULTI, |
1251 | OVS_FLOW_CMD_NEW) < 0) | 1328 | OVS_FLOW_CMD_NEW, ufid_flags) < 0) |
1252 | break; | 1329 | break; |
1253 | 1330 | ||
1254 | cb->args[0] = bucket; | 1331 | cb->args[0] = bucket; |
@@ -1264,6 +1341,8 @@ static const struct nla_policy flow_policy[OVS_FLOW_ATTR_MAX + 1] = { | |||
1264 | [OVS_FLOW_ATTR_ACTIONS] = { .type = NLA_NESTED }, | 1341 | [OVS_FLOW_ATTR_ACTIONS] = { .type = NLA_NESTED }, |
1265 | [OVS_FLOW_ATTR_CLEAR] = { .type = NLA_FLAG }, | 1342 | [OVS_FLOW_ATTR_CLEAR] = { .type = NLA_FLAG }, |
1266 | [OVS_FLOW_ATTR_PROBE] = { .type = NLA_FLAG }, | 1343 | [OVS_FLOW_ATTR_PROBE] = { .type = NLA_FLAG }, |
1344 | [OVS_FLOW_ATTR_UFID] = { .type = NLA_UNSPEC, .len = 1 }, | ||
1345 | [OVS_FLOW_ATTR_UFID_FLAGS] = { .type = NLA_U32 }, | ||
1267 | }; | 1346 | }; |
1268 | 1347 | ||
1269 | static const struct genl_ops dp_flow_genl_ops[] = { | 1348 | static const struct genl_ops dp_flow_genl_ops[] = { |
@@ -1349,7 +1428,8 @@ static int ovs_dp_cmd_fill_info(struct datapath *dp, struct sk_buff *skb, | |||
1349 | if (nla_put_u32(skb, OVS_DP_ATTR_USER_FEATURES, dp->user_features)) | 1428 | if (nla_put_u32(skb, OVS_DP_ATTR_USER_FEATURES, dp->user_features)) |
1350 | goto nla_put_failure; | 1429 | goto nla_put_failure; |
1351 | 1430 | ||
1352 | return genlmsg_end(skb, ovs_header); | 1431 | genlmsg_end(skb, ovs_header); |
1432 | return 0; | ||
1353 | 1433 | ||
1354 | nla_put_failure: | 1434 | nla_put_failure: |
1355 | genlmsg_cancel(skb, ovs_header); | 1435 | genlmsg_cancel(skb, ovs_header); |
@@ -1723,7 +1803,8 @@ static int ovs_vport_cmd_fill_info(struct vport *vport, struct sk_buff *skb, | |||
1723 | if (err == -EMSGSIZE) | 1803 | if (err == -EMSGSIZE) |
1724 | goto error; | 1804 | goto error; |
1725 | 1805 | ||
1726 | return genlmsg_end(skb, ovs_header); | 1806 | genlmsg_end(skb, ovs_header); |
1807 | return 0; | ||
1727 | 1808 | ||
1728 | nla_put_failure: | 1809 | nla_put_failure: |
1729 | err = -EMSGSIZE; | 1810 | err = -EMSGSIZE; |