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