diff options
Diffstat (limited to 'net/openvswitch/datapath.c')
-rw-r--r-- | net/openvswitch/datapath.c | 78 |
1 files changed, 75 insertions, 3 deletions
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c index f14816b80b80..bbd310646bc8 100644 --- a/net/openvswitch/datapath.c +++ b/net/openvswitch/datapath.c | |||
@@ -362,6 +362,14 @@ static int queue_gso_packets(struct net *net, int dp_ifindex, | |||
362 | static size_t key_attr_size(void) | 362 | static size_t key_attr_size(void) |
363 | { | 363 | { |
364 | return nla_total_size(4) /* OVS_KEY_ATTR_PRIORITY */ | 364 | return nla_total_size(4) /* OVS_KEY_ATTR_PRIORITY */ |
365 | + nla_total_size(0) /* OVS_KEY_ATTR_TUNNEL */ | ||
366 | + nla_total_size(8) /* OVS_TUNNEL_KEY_ATTR_ID */ | ||
367 | + nla_total_size(4) /* OVS_TUNNEL_KEY_ATTR_IPV4_SRC */ | ||
368 | + nla_total_size(4) /* OVS_TUNNEL_KEY_ATTR_IPV4_DST */ | ||
369 | + nla_total_size(1) /* OVS_TUNNEL_KEY_ATTR_TOS */ | ||
370 | + nla_total_size(1) /* OVS_TUNNEL_KEY_ATTR_TTL */ | ||
371 | + nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT */ | ||
372 | + nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_CSUM */ | ||
365 | + nla_total_size(4) /* OVS_KEY_ATTR_IN_PORT */ | 373 | + nla_total_size(4) /* OVS_KEY_ATTR_IN_PORT */ |
366 | + nla_total_size(4) /* OVS_KEY_ATTR_SKB_MARK */ | 374 | + nla_total_size(4) /* OVS_KEY_ATTR_SKB_MARK */ |
367 | + nla_total_size(12) /* OVS_KEY_ATTR_ETHERNET */ | 375 | + nla_total_size(12) /* OVS_KEY_ATTR_ETHERNET */ |
@@ -600,8 +608,30 @@ static int validate_tp_port(const struct sw_flow_key *flow_key) | |||
600 | return -EINVAL; | 608 | return -EINVAL; |
601 | } | 609 | } |
602 | 610 | ||
611 | static int validate_and_copy_set_tun(const struct nlattr *attr, | ||
612 | struct sw_flow_actions **sfa) | ||
613 | { | ||
614 | struct ovs_key_ipv4_tunnel tun_key; | ||
615 | int err, start; | ||
616 | |||
617 | err = ovs_ipv4_tun_from_nlattr(nla_data(attr), &tun_key); | ||
618 | if (err) | ||
619 | return err; | ||
620 | |||
621 | start = add_nested_action_start(sfa, OVS_ACTION_ATTR_SET); | ||
622 | if (start < 0) | ||
623 | return start; | ||
624 | |||
625 | err = add_action(sfa, OVS_KEY_ATTR_IPV4_TUNNEL, &tun_key, sizeof(tun_key)); | ||
626 | add_nested_action_end(*sfa, start); | ||
627 | |||
628 | return err; | ||
629 | } | ||
630 | |||
603 | static int validate_set(const struct nlattr *a, | 631 | static int validate_set(const struct nlattr *a, |
604 | const struct sw_flow_key *flow_key) | 632 | const struct sw_flow_key *flow_key, |
633 | struct sw_flow_actions **sfa, | ||
634 | bool *set_tun) | ||
605 | { | 635 | { |
606 | const struct nlattr *ovs_key = nla_data(a); | 636 | const struct nlattr *ovs_key = nla_data(a); |
607 | int key_type = nla_type(ovs_key); | 637 | int key_type = nla_type(ovs_key); |
@@ -611,18 +641,27 @@ static int validate_set(const struct nlattr *a, | |||
611 | return -EINVAL; | 641 | return -EINVAL; |
612 | 642 | ||
613 | if (key_type > OVS_KEY_ATTR_MAX || | 643 | if (key_type > OVS_KEY_ATTR_MAX || |
614 | nla_len(ovs_key) != ovs_key_lens[key_type]) | 644 | (ovs_key_lens[key_type] != nla_len(ovs_key) && |
645 | ovs_key_lens[key_type] != -1)) | ||
615 | return -EINVAL; | 646 | return -EINVAL; |
616 | 647 | ||
617 | switch (key_type) { | 648 | switch (key_type) { |
618 | const struct ovs_key_ipv4 *ipv4_key; | 649 | const struct ovs_key_ipv4 *ipv4_key; |
619 | const struct ovs_key_ipv6 *ipv6_key; | 650 | const struct ovs_key_ipv6 *ipv6_key; |
651 | int err; | ||
620 | 652 | ||
621 | case OVS_KEY_ATTR_PRIORITY: | 653 | case OVS_KEY_ATTR_PRIORITY: |
622 | case OVS_KEY_ATTR_SKB_MARK: | 654 | case OVS_KEY_ATTR_SKB_MARK: |
623 | case OVS_KEY_ATTR_ETHERNET: | 655 | case OVS_KEY_ATTR_ETHERNET: |
624 | break; | 656 | break; |
625 | 657 | ||
658 | case OVS_KEY_ATTR_TUNNEL: | ||
659 | *set_tun = true; | ||
660 | err = validate_and_copy_set_tun(a, sfa); | ||
661 | if (err) | ||
662 | return err; | ||
663 | break; | ||
664 | |||
626 | case OVS_KEY_ATTR_IPV4: | 665 | case OVS_KEY_ATTR_IPV4: |
627 | if (flow_key->eth.type != htons(ETH_P_IP)) | 666 | if (flow_key->eth.type != htons(ETH_P_IP)) |
628 | return -EINVAL; | 667 | return -EINVAL; |
@@ -771,7 +810,7 @@ static int validate_and_copy_actions(const struct nlattr *attr, | |||
771 | break; | 810 | break; |
772 | 811 | ||
773 | case OVS_ACTION_ATTR_SET: | 812 | case OVS_ACTION_ATTR_SET: |
774 | err = validate_set(a, key); | 813 | err = validate_set(a, key, sfa, &skip_copy); |
775 | if (err) | 814 | if (err) |
776 | return err; | 815 | return err; |
777 | break; | 816 | break; |
@@ -993,6 +1032,33 @@ static int sample_action_to_attr(const struct nlattr *attr, struct sk_buff *skb) | |||
993 | return err; | 1032 | return err; |
994 | } | 1033 | } |
995 | 1034 | ||
1035 | static int set_action_to_attr(const struct nlattr *a, struct sk_buff *skb) | ||
1036 | { | ||
1037 | const struct nlattr *ovs_key = nla_data(a); | ||
1038 | int key_type = nla_type(ovs_key); | ||
1039 | struct nlattr *start; | ||
1040 | int err; | ||
1041 | |||
1042 | switch (key_type) { | ||
1043 | case OVS_KEY_ATTR_IPV4_TUNNEL: | ||
1044 | start = nla_nest_start(skb, OVS_ACTION_ATTR_SET); | ||
1045 | if (!start) | ||
1046 | return -EMSGSIZE; | ||
1047 | |||
1048 | err = ovs_ipv4_tun_to_nlattr(skb, nla_data(ovs_key)); | ||
1049 | if (err) | ||
1050 | return err; | ||
1051 | nla_nest_end(skb, start); | ||
1052 | break; | ||
1053 | default: | ||
1054 | if (nla_put(skb, OVS_ACTION_ATTR_SET, nla_len(a), ovs_key)) | ||
1055 | return -EMSGSIZE; | ||
1056 | break; | ||
1057 | } | ||
1058 | |||
1059 | return 0; | ||
1060 | } | ||
1061 | |||
996 | static int actions_to_attr(const struct nlattr *attr, int len, struct sk_buff *skb) | 1062 | static int actions_to_attr(const struct nlattr *attr, int len, struct sk_buff *skb) |
997 | { | 1063 | { |
998 | const struct nlattr *a; | 1064 | const struct nlattr *a; |
@@ -1002,6 +1068,12 @@ static int actions_to_attr(const struct nlattr *attr, int len, struct sk_buff *s | |||
1002 | int type = nla_type(a); | 1068 | int type = nla_type(a); |
1003 | 1069 | ||
1004 | switch (type) { | 1070 | switch (type) { |
1071 | case OVS_ACTION_ATTR_SET: | ||
1072 | err = set_action_to_attr(a, skb); | ||
1073 | if (err) | ||
1074 | return err; | ||
1075 | break; | ||
1076 | |||
1005 | case OVS_ACTION_ATTR_SAMPLE: | 1077 | case OVS_ACTION_ATTR_SAMPLE: |
1006 | err = sample_action_to_attr(a, skb); | 1078 | err = sample_action_to_attr(a, skb); |
1007 | if (err) | 1079 | if (err) |