diff options
Diffstat (limited to 'net/openvswitch')
-rw-r--r-- | net/openvswitch/actions.c | 40 | ||||
-rw-r--r-- | net/openvswitch/conntrack.c | 69 | ||||
-rw-r--r-- | net/openvswitch/datapath.c | 42 | ||||
-rw-r--r-- | net/openvswitch/datapath.h | 5 | ||||
-rw-r--r-- | net/openvswitch/flow_netlink.c | 9 | ||||
-rw-r--r-- | net/openvswitch/vport-internal_dev.c | 2 | ||||
-rw-r--r-- | net/openvswitch/vport.c | 1 |
7 files changed, 125 insertions, 43 deletions
diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c index 9a3eb7a0ebf4..1ecbd7715f6d 100644 --- a/net/openvswitch/actions.c +++ b/net/openvswitch/actions.c | |||
@@ -750,6 +750,14 @@ static void do_output(struct datapath *dp, struct sk_buff *skb, int out_port, | |||
750 | 750 | ||
751 | if (likely(vport)) { | 751 | if (likely(vport)) { |
752 | u16 mru = OVS_CB(skb)->mru; | 752 | u16 mru = OVS_CB(skb)->mru; |
753 | u32 cutlen = OVS_CB(skb)->cutlen; | ||
754 | |||
755 | if (unlikely(cutlen > 0)) { | ||
756 | if (skb->len - cutlen > ETH_HLEN) | ||
757 | pskb_trim(skb, skb->len - cutlen); | ||
758 | else | ||
759 | pskb_trim(skb, ETH_HLEN); | ||
760 | } | ||
753 | 761 | ||
754 | if (likely(!mru || (skb->len <= mru + ETH_HLEN))) { | 762 | if (likely(!mru || (skb->len <= mru + ETH_HLEN))) { |
755 | ovs_vport_send(vport, skb); | 763 | ovs_vport_send(vport, skb); |
@@ -775,7 +783,8 @@ static void do_output(struct datapath *dp, struct sk_buff *skb, int out_port, | |||
775 | 783 | ||
776 | static int output_userspace(struct datapath *dp, struct sk_buff *skb, | 784 | static int output_userspace(struct datapath *dp, struct sk_buff *skb, |
777 | struct sw_flow_key *key, const struct nlattr *attr, | 785 | struct sw_flow_key *key, const struct nlattr *attr, |
778 | const struct nlattr *actions, int actions_len) | 786 | const struct nlattr *actions, int actions_len, |
787 | uint32_t cutlen) | ||
779 | { | 788 | { |
780 | struct dp_upcall_info upcall; | 789 | struct dp_upcall_info upcall; |
781 | const struct nlattr *a; | 790 | const struct nlattr *a; |
@@ -822,7 +831,7 @@ static int output_userspace(struct datapath *dp, struct sk_buff *skb, | |||
822 | } /* End of switch. */ | 831 | } /* End of switch. */ |
823 | } | 832 | } |
824 | 833 | ||
825 | return ovs_dp_upcall(dp, skb, key, &upcall); | 834 | return ovs_dp_upcall(dp, skb, key, &upcall, cutlen); |
826 | } | 835 | } |
827 | 836 | ||
828 | static int sample(struct datapath *dp, struct sk_buff *skb, | 837 | static int sample(struct datapath *dp, struct sk_buff *skb, |
@@ -832,6 +841,7 @@ static int sample(struct datapath *dp, struct sk_buff *skb, | |||
832 | const struct nlattr *acts_list = NULL; | 841 | const struct nlattr *acts_list = NULL; |
833 | const struct nlattr *a; | 842 | const struct nlattr *a; |
834 | int rem; | 843 | int rem; |
844 | u32 cutlen = 0; | ||
835 | 845 | ||
836 | for (a = nla_data(attr), rem = nla_len(attr); rem > 0; | 846 | for (a = nla_data(attr), rem = nla_len(attr); rem > 0; |
837 | a = nla_next(a, &rem)) { | 847 | a = nla_next(a, &rem)) { |
@@ -858,13 +868,24 @@ static int sample(struct datapath *dp, struct sk_buff *skb, | |||
858 | return 0; | 868 | return 0; |
859 | 869 | ||
860 | /* The only known usage of sample action is having a single user-space | 870 | /* The only known usage of sample action is having a single user-space |
871 | * action, or having a truncate action followed by a single user-space | ||
861 | * action. Treat this usage as a special case. | 872 | * action. Treat this usage as a special case. |
862 | * The output_userspace() should clone the skb to be sent to the | 873 | * The output_userspace() should clone the skb to be sent to the |
863 | * user space. This skb will be consumed by its caller. | 874 | * user space. This skb will be consumed by its caller. |
864 | */ | 875 | */ |
876 | if (unlikely(nla_type(a) == OVS_ACTION_ATTR_TRUNC)) { | ||
877 | struct ovs_action_trunc *trunc = nla_data(a); | ||
878 | |||
879 | if (skb->len > trunc->max_len) | ||
880 | cutlen = skb->len - trunc->max_len; | ||
881 | |||
882 | a = nla_next(a, &rem); | ||
883 | } | ||
884 | |||
865 | if (likely(nla_type(a) == OVS_ACTION_ATTR_USERSPACE && | 885 | if (likely(nla_type(a) == OVS_ACTION_ATTR_USERSPACE && |
866 | nla_is_last(a, rem))) | 886 | nla_is_last(a, rem))) |
867 | return output_userspace(dp, skb, key, a, actions, actions_len); | 887 | return output_userspace(dp, skb, key, a, actions, |
888 | actions_len, cutlen); | ||
868 | 889 | ||
869 | skb = skb_clone(skb, GFP_ATOMIC); | 890 | skb = skb_clone(skb, GFP_ATOMIC); |
870 | if (!skb) | 891 | if (!skb) |
@@ -1051,6 +1072,7 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, | |||
1051 | if (out_skb) | 1072 | if (out_skb) |
1052 | do_output(dp, out_skb, prev_port, key); | 1073 | do_output(dp, out_skb, prev_port, key); |
1053 | 1074 | ||
1075 | OVS_CB(skb)->cutlen = 0; | ||
1054 | prev_port = -1; | 1076 | prev_port = -1; |
1055 | } | 1077 | } |
1056 | 1078 | ||
@@ -1059,8 +1081,18 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, | |||
1059 | prev_port = nla_get_u32(a); | 1081 | prev_port = nla_get_u32(a); |
1060 | break; | 1082 | break; |
1061 | 1083 | ||
1084 | case OVS_ACTION_ATTR_TRUNC: { | ||
1085 | struct ovs_action_trunc *trunc = nla_data(a); | ||
1086 | |||
1087 | if (skb->len > trunc->max_len) | ||
1088 | OVS_CB(skb)->cutlen = skb->len - trunc->max_len; | ||
1089 | break; | ||
1090 | } | ||
1091 | |||
1062 | case OVS_ACTION_ATTR_USERSPACE: | 1092 | case OVS_ACTION_ATTR_USERSPACE: |
1063 | output_userspace(dp, skb, key, a, attr, len); | 1093 | output_userspace(dp, skb, key, a, attr, |
1094 | len, OVS_CB(skb)->cutlen); | ||
1095 | OVS_CB(skb)->cutlen = 0; | ||
1064 | break; | 1096 | break; |
1065 | 1097 | ||
1066 | case OVS_ACTION_ATTR_HASH: | 1098 | case OVS_ACTION_ATTR_HASH: |
diff --git a/net/openvswitch/conntrack.c b/net/openvswitch/conntrack.c index d84312584ee4..b4069a90e375 100644 --- a/net/openvswitch/conntrack.c +++ b/net/openvswitch/conntrack.c | |||
@@ -834,6 +834,17 @@ static int ovs_ct_lookup(struct net *net, struct sw_flow_key *key, | |||
834 | return 0; | 834 | return 0; |
835 | } | 835 | } |
836 | 836 | ||
837 | static bool labels_nonzero(const struct ovs_key_ct_labels *labels) | ||
838 | { | ||
839 | size_t i; | ||
840 | |||
841 | for (i = 0; i < sizeof(*labels); i++) | ||
842 | if (labels->ct_labels[i]) | ||
843 | return true; | ||
844 | |||
845 | return false; | ||
846 | } | ||
847 | |||
837 | /* Lookup connection and confirm if unconfirmed. */ | 848 | /* Lookup connection and confirm if unconfirmed. */ |
838 | static int ovs_ct_commit(struct net *net, struct sw_flow_key *key, | 849 | static int ovs_ct_commit(struct net *net, struct sw_flow_key *key, |
839 | const struct ovs_conntrack_info *info, | 850 | const struct ovs_conntrack_info *info, |
@@ -844,24 +855,32 @@ static int ovs_ct_commit(struct net *net, struct sw_flow_key *key, | |||
844 | err = __ovs_ct_lookup(net, key, info, skb); | 855 | err = __ovs_ct_lookup(net, key, info, skb); |
845 | if (err) | 856 | if (err) |
846 | return err; | 857 | return err; |
847 | /* This is a no-op if the connection has already been confirmed. */ | 858 | |
859 | /* Apply changes before confirming the connection so that the initial | ||
860 | * conntrack NEW netlink event carries the values given in the CT | ||
861 | * action. | ||
862 | */ | ||
863 | if (info->mark.mask) { | ||
864 | err = ovs_ct_set_mark(skb, key, info->mark.value, | ||
865 | info->mark.mask); | ||
866 | if (err) | ||
867 | return err; | ||
868 | } | ||
869 | if (labels_nonzero(&info->labels.mask)) { | ||
870 | err = ovs_ct_set_labels(skb, key, &info->labels.value, | ||
871 | &info->labels.mask); | ||
872 | if (err) | ||
873 | return err; | ||
874 | } | ||
875 | /* This will take care of sending queued events even if the connection | ||
876 | * is already confirmed. | ||
877 | */ | ||
848 | if (nf_conntrack_confirm(skb) != NF_ACCEPT) | 878 | if (nf_conntrack_confirm(skb) != NF_ACCEPT) |
849 | return -EINVAL; | 879 | return -EINVAL; |
850 | 880 | ||
851 | return 0; | 881 | return 0; |
852 | } | 882 | } |
853 | 883 | ||
854 | static bool labels_nonzero(const struct ovs_key_ct_labels *labels) | ||
855 | { | ||
856 | size_t i; | ||
857 | |||
858 | for (i = 0; i < sizeof(*labels); i++) | ||
859 | if (labels->ct_labels[i]) | ||
860 | return true; | ||
861 | |||
862 | return false; | ||
863 | } | ||
864 | |||
865 | /* Returns 0 on success, -EINPROGRESS if 'skb' is stolen, or other nonzero | 884 | /* Returns 0 on success, -EINPROGRESS if 'skb' is stolen, or other nonzero |
866 | * value if 'skb' is freed. | 885 | * value if 'skb' is freed. |
867 | */ | 886 | */ |
@@ -886,19 +905,7 @@ int ovs_ct_execute(struct net *net, struct sk_buff *skb, | |||
886 | err = ovs_ct_commit(net, key, info, skb); | 905 | err = ovs_ct_commit(net, key, info, skb); |
887 | else | 906 | else |
888 | err = ovs_ct_lookup(net, key, info, skb); | 907 | err = ovs_ct_lookup(net, key, info, skb); |
889 | if (err) | ||
890 | goto err; | ||
891 | 908 | ||
892 | if (info->mark.mask) { | ||
893 | err = ovs_ct_set_mark(skb, key, info->mark.value, | ||
894 | info->mark.mask); | ||
895 | if (err) | ||
896 | goto err; | ||
897 | } | ||
898 | if (labels_nonzero(&info->labels.mask)) | ||
899 | err = ovs_ct_set_labels(skb, key, &info->labels.value, | ||
900 | &info->labels.mask); | ||
901 | err: | ||
902 | skb_push(skb, nh_ofs); | 909 | skb_push(skb, nh_ofs); |
903 | if (err) | 910 | if (err) |
904 | kfree_skb(skb); | 911 | kfree_skb(skb); |
@@ -1155,6 +1162,20 @@ static int parse_ct(const struct nlattr *attr, struct ovs_conntrack_info *info, | |||
1155 | } | 1162 | } |
1156 | } | 1163 | } |
1157 | 1164 | ||
1165 | #ifdef CONFIG_NF_CONNTRACK_MARK | ||
1166 | if (!info->commit && info->mark.mask) { | ||
1167 | OVS_NLERR(log, | ||
1168 | "Setting conntrack mark requires 'commit' flag."); | ||
1169 | return -EINVAL; | ||
1170 | } | ||
1171 | #endif | ||
1172 | #ifdef CONFIG_NF_CONNTRACK_LABELS | ||
1173 | if (!info->commit && labels_nonzero(&info->labels.mask)) { | ||
1174 | OVS_NLERR(log, | ||
1175 | "Setting conntrack labels requires 'commit' flag."); | ||
1176 | return -EINVAL; | ||
1177 | } | ||
1178 | #endif | ||
1158 | if (rem > 0) { | 1179 | if (rem > 0) { |
1159 | OVS_NLERR(log, "Conntrack attr has %d unknown bytes", rem); | 1180 | OVS_NLERR(log, "Conntrack attr has %d unknown bytes", rem); |
1160 | return -EINVAL; | 1181 | return -EINVAL; |
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c index 856bd8dba676..524c0fd3078e 100644 --- a/net/openvswitch/datapath.c +++ b/net/openvswitch/datapath.c | |||
@@ -137,10 +137,12 @@ EXPORT_SYMBOL_GPL(lockdep_ovsl_is_held); | |||
137 | static struct vport *new_vport(const struct vport_parms *); | 137 | static struct vport *new_vport(const struct vport_parms *); |
138 | static int queue_gso_packets(struct datapath *dp, struct sk_buff *, | 138 | static int queue_gso_packets(struct datapath *dp, struct sk_buff *, |
139 | const struct sw_flow_key *, | 139 | const struct sw_flow_key *, |
140 | const struct dp_upcall_info *); | 140 | const struct dp_upcall_info *, |
141 | uint32_t cutlen); | ||
141 | static int queue_userspace_packet(struct datapath *dp, struct sk_buff *, | 142 | static int queue_userspace_packet(struct datapath *dp, struct sk_buff *, |
142 | const struct sw_flow_key *, | 143 | const struct sw_flow_key *, |
143 | const struct dp_upcall_info *); | 144 | const struct dp_upcall_info *, |
145 | uint32_t cutlen); | ||
144 | 146 | ||
145 | /* Must be called with rcu_read_lock. */ | 147 | /* Must be called with rcu_read_lock. */ |
146 | static struct datapath *get_dp_rcu(struct net *net, int dp_ifindex) | 148 | static struct datapath *get_dp_rcu(struct net *net, int dp_ifindex) |
@@ -275,7 +277,7 @@ void ovs_dp_process_packet(struct sk_buff *skb, struct sw_flow_key *key) | |||
275 | upcall.cmd = OVS_PACKET_CMD_MISS; | 277 | upcall.cmd = OVS_PACKET_CMD_MISS; |
276 | upcall.portid = ovs_vport_find_upcall_portid(p, skb); | 278 | upcall.portid = ovs_vport_find_upcall_portid(p, skb); |
277 | upcall.mru = OVS_CB(skb)->mru; | 279 | upcall.mru = OVS_CB(skb)->mru; |
278 | error = ovs_dp_upcall(dp, skb, key, &upcall); | 280 | error = ovs_dp_upcall(dp, skb, key, &upcall, 0); |
279 | if (unlikely(error)) | 281 | if (unlikely(error)) |
280 | kfree_skb(skb); | 282 | kfree_skb(skb); |
281 | else | 283 | else |
@@ -300,7 +302,8 @@ out: | |||
300 | 302 | ||
301 | int ovs_dp_upcall(struct datapath *dp, struct sk_buff *skb, | 303 | int ovs_dp_upcall(struct datapath *dp, struct sk_buff *skb, |
302 | const struct sw_flow_key *key, | 304 | const struct sw_flow_key *key, |
303 | const struct dp_upcall_info *upcall_info) | 305 | const struct dp_upcall_info *upcall_info, |
306 | uint32_t cutlen) | ||
304 | { | 307 | { |
305 | struct dp_stats_percpu *stats; | 308 | struct dp_stats_percpu *stats; |
306 | int err; | 309 | int err; |
@@ -311,9 +314,9 @@ int ovs_dp_upcall(struct datapath *dp, struct sk_buff *skb, | |||
311 | } | 314 | } |
312 | 315 | ||
313 | if (!skb_is_gso(skb)) | 316 | if (!skb_is_gso(skb)) |
314 | err = queue_userspace_packet(dp, skb, key, upcall_info); | 317 | err = queue_userspace_packet(dp, skb, key, upcall_info, cutlen); |
315 | else | 318 | else |
316 | err = queue_gso_packets(dp, skb, key, upcall_info); | 319 | err = queue_gso_packets(dp, skb, key, upcall_info, cutlen); |
317 | if (err) | 320 | if (err) |
318 | goto err; | 321 | goto err; |
319 | 322 | ||
@@ -331,7 +334,8 @@ err: | |||
331 | 334 | ||
332 | static int queue_gso_packets(struct datapath *dp, struct sk_buff *skb, | 335 | static int queue_gso_packets(struct datapath *dp, struct sk_buff *skb, |
333 | const struct sw_flow_key *key, | 336 | const struct sw_flow_key *key, |
334 | const struct dp_upcall_info *upcall_info) | 337 | const struct dp_upcall_info *upcall_info, |
338 | uint32_t cutlen) | ||
335 | { | 339 | { |
336 | unsigned short gso_type = skb_shinfo(skb)->gso_type; | 340 | unsigned short gso_type = skb_shinfo(skb)->gso_type; |
337 | struct sw_flow_key later_key; | 341 | struct sw_flow_key later_key; |
@@ -360,7 +364,7 @@ static int queue_gso_packets(struct datapath *dp, struct sk_buff *skb, | |||
360 | if (gso_type & SKB_GSO_UDP && skb != segs) | 364 | if (gso_type & SKB_GSO_UDP && skb != segs) |
361 | key = &later_key; | 365 | key = &later_key; |
362 | 366 | ||
363 | err = queue_userspace_packet(dp, skb, key, upcall_info); | 367 | err = queue_userspace_packet(dp, skb, key, upcall_info, cutlen); |
364 | if (err) | 368 | if (err) |
365 | break; | 369 | break; |
366 | 370 | ||
@@ -383,7 +387,8 @@ static size_t upcall_msg_size(const struct dp_upcall_info *upcall_info, | |||
383 | { | 387 | { |
384 | size_t size = NLMSG_ALIGN(sizeof(struct ovs_header)) | 388 | size_t size = NLMSG_ALIGN(sizeof(struct ovs_header)) |
385 | + nla_total_size(hdrlen) /* OVS_PACKET_ATTR_PACKET */ | 389 | + nla_total_size(hdrlen) /* OVS_PACKET_ATTR_PACKET */ |
386 | + nla_total_size(ovs_key_attr_size()); /* OVS_PACKET_ATTR_KEY */ | 390 | + nla_total_size(ovs_key_attr_size()) /* OVS_PACKET_ATTR_KEY */ |
391 | + nla_total_size(sizeof(unsigned int)); /* OVS_PACKET_ATTR_LEN */ | ||
387 | 392 | ||
388 | /* OVS_PACKET_ATTR_USERDATA */ | 393 | /* OVS_PACKET_ATTR_USERDATA */ |
389 | if (upcall_info->userdata) | 394 | if (upcall_info->userdata) |
@@ -416,7 +421,8 @@ static void pad_packet(struct datapath *dp, struct sk_buff *skb) | |||
416 | 421 | ||
417 | static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb, | 422 | static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb, |
418 | const struct sw_flow_key *key, | 423 | const struct sw_flow_key *key, |
419 | const struct dp_upcall_info *upcall_info) | 424 | const struct dp_upcall_info *upcall_info, |
425 | uint32_t cutlen) | ||
420 | { | 426 | { |
421 | struct ovs_header *upcall; | 427 | struct ovs_header *upcall; |
422 | struct sk_buff *nskb = NULL; | 428 | struct sk_buff *nskb = NULL; |
@@ -461,7 +467,7 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb, | |||
461 | else | 467 | else |
462 | hlen = skb->len; | 468 | hlen = skb->len; |
463 | 469 | ||
464 | len = upcall_msg_size(upcall_info, hlen); | 470 | len = upcall_msg_size(upcall_info, hlen - cutlen); |
465 | user_skb = genlmsg_new(len, GFP_ATOMIC); | 471 | user_skb = genlmsg_new(len, GFP_ATOMIC); |
466 | if (!user_skb) { | 472 | if (!user_skb) { |
467 | err = -ENOMEM; | 473 | err = -ENOMEM; |
@@ -509,15 +515,25 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb, | |||
509 | pad_packet(dp, user_skb); | 515 | pad_packet(dp, user_skb); |
510 | } | 516 | } |
511 | 517 | ||
518 | /* Add OVS_PACKET_ATTR_LEN when packet is truncated */ | ||
519 | if (cutlen > 0) { | ||
520 | if (nla_put_u32(user_skb, OVS_PACKET_ATTR_LEN, | ||
521 | skb->len)) { | ||
522 | err = -ENOBUFS; | ||
523 | goto out; | ||
524 | } | ||
525 | pad_packet(dp, user_skb); | ||
526 | } | ||
527 | |||
512 | /* Only reserve room for attribute header, packet data is added | 528 | /* Only reserve room for attribute header, packet data is added |
513 | * in skb_zerocopy() */ | 529 | * in skb_zerocopy() */ |
514 | if (!(nla = nla_reserve(user_skb, OVS_PACKET_ATTR_PACKET, 0))) { | 530 | if (!(nla = nla_reserve(user_skb, OVS_PACKET_ATTR_PACKET, 0))) { |
515 | err = -ENOBUFS; | 531 | err = -ENOBUFS; |
516 | goto out; | 532 | goto out; |
517 | } | 533 | } |
518 | nla->nla_len = nla_attr_size(skb->len); | 534 | nla->nla_len = nla_attr_size(skb->len - cutlen); |
519 | 535 | ||
520 | err = skb_zerocopy(user_skb, skb, skb->len, hlen); | 536 | err = skb_zerocopy(user_skb, skb, skb->len - cutlen, hlen); |
521 | if (err) | 537 | if (err) |
522 | goto out; | 538 | goto out; |
523 | 539 | ||
diff --git a/net/openvswitch/datapath.h b/net/openvswitch/datapath.h index 427e39a045cf..ab85c1cae255 100644 --- a/net/openvswitch/datapath.h +++ b/net/openvswitch/datapath.h | |||
@@ -100,11 +100,13 @@ struct datapath { | |||
100 | * @input_vport: The original vport packet came in on. This value is cached | 100 | * @input_vport: The original vport packet came in on. This value is cached |
101 | * when a packet is received by OVS. | 101 | * when a packet is received by OVS. |
102 | * @mru: The maximum received fragement size; 0 if the packet is not | 102 | * @mru: The maximum received fragement size; 0 if the packet is not |
103 | * @cutlen: The number of bytes from the packet end to be removed. | ||
103 | * fragmented. | 104 | * fragmented. |
104 | */ | 105 | */ |
105 | struct ovs_skb_cb { | 106 | struct ovs_skb_cb { |
106 | struct vport *input_vport; | 107 | struct vport *input_vport; |
107 | u16 mru; | 108 | u16 mru; |
109 | u32 cutlen; | ||
108 | }; | 110 | }; |
109 | #define OVS_CB(skb) ((struct ovs_skb_cb *)(skb)->cb) | 111 | #define OVS_CB(skb) ((struct ovs_skb_cb *)(skb)->cb) |
110 | 112 | ||
@@ -194,7 +196,8 @@ extern struct genl_family dp_vport_genl_family; | |||
194 | void ovs_dp_process_packet(struct sk_buff *skb, struct sw_flow_key *key); | 196 | void ovs_dp_process_packet(struct sk_buff *skb, struct sw_flow_key *key); |
195 | void ovs_dp_detach_port(struct vport *); | 197 | void ovs_dp_detach_port(struct vport *); |
196 | int ovs_dp_upcall(struct datapath *, struct sk_buff *, | 198 | int ovs_dp_upcall(struct datapath *, struct sk_buff *, |
197 | const struct sw_flow_key *, const struct dp_upcall_info *); | 199 | const struct sw_flow_key *, const struct dp_upcall_info *, |
200 | uint32_t cutlen); | ||
198 | 201 | ||
199 | const char *ovs_dp_name(const struct datapath *dp); | 202 | const char *ovs_dp_name(const struct datapath *dp); |
200 | struct sk_buff *ovs_vport_cmd_build_info(struct vport *, u32 pid, u32 seq, | 203 | struct sk_buff *ovs_vport_cmd_build_info(struct vport *, u32 pid, u32 seq, |
diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c index 0bb650f4f219..c78a6a1476fb 100644 --- a/net/openvswitch/flow_netlink.c +++ b/net/openvswitch/flow_netlink.c | |||
@@ -2229,6 +2229,7 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, | |||
2229 | [OVS_ACTION_ATTR_SAMPLE] = (u32)-1, | 2229 | [OVS_ACTION_ATTR_SAMPLE] = (u32)-1, |
2230 | [OVS_ACTION_ATTR_HASH] = sizeof(struct ovs_action_hash), | 2230 | [OVS_ACTION_ATTR_HASH] = sizeof(struct ovs_action_hash), |
2231 | [OVS_ACTION_ATTR_CT] = (u32)-1, | 2231 | [OVS_ACTION_ATTR_CT] = (u32)-1, |
2232 | [OVS_ACTION_ATTR_TRUNC] = sizeof(struct ovs_action_trunc), | ||
2232 | }; | 2233 | }; |
2233 | const struct ovs_action_push_vlan *vlan; | 2234 | const struct ovs_action_push_vlan *vlan; |
2234 | int type = nla_type(a); | 2235 | int type = nla_type(a); |
@@ -2255,6 +2256,14 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, | |||
2255 | return -EINVAL; | 2256 | return -EINVAL; |
2256 | break; | 2257 | break; |
2257 | 2258 | ||
2259 | case OVS_ACTION_ATTR_TRUNC: { | ||
2260 | const struct ovs_action_trunc *trunc = nla_data(a); | ||
2261 | |||
2262 | if (trunc->max_len < ETH_HLEN) | ||
2263 | return -EINVAL; | ||
2264 | break; | ||
2265 | } | ||
2266 | |||
2258 | case OVS_ACTION_ATTR_HASH: { | 2267 | case OVS_ACTION_ATTR_HASH: { |
2259 | const struct ovs_action_hash *act_hash = nla_data(a); | 2268 | const struct ovs_action_hash *act_hash = nla_data(a); |
2260 | 2269 | ||
diff --git a/net/openvswitch/vport-internal_dev.c b/net/openvswitch/vport-internal_dev.c index 2ee48e447b72..434e04c3a189 100644 --- a/net/openvswitch/vport-internal_dev.c +++ b/net/openvswitch/vport-internal_dev.c | |||
@@ -195,7 +195,7 @@ static struct vport *internal_dev_create(const struct vport_parms *parms) | |||
195 | } | 195 | } |
196 | 196 | ||
197 | vport->dev = alloc_netdev(sizeof(struct internal_dev), | 197 | vport->dev = alloc_netdev(sizeof(struct internal_dev), |
198 | parms->name, NET_NAME_UNKNOWN, do_setup); | 198 | parms->name, NET_NAME_USER, do_setup); |
199 | if (!vport->dev) { | 199 | if (!vport->dev) { |
200 | err = -ENOMEM; | 200 | err = -ENOMEM; |
201 | goto error_free_vport; | 201 | goto error_free_vport; |
diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c index 31cbc8c5c7db..6b21fd068d87 100644 --- a/net/openvswitch/vport.c +++ b/net/openvswitch/vport.c | |||
@@ -444,6 +444,7 @@ int ovs_vport_receive(struct vport *vport, struct sk_buff *skb, | |||
444 | 444 | ||
445 | OVS_CB(skb)->input_vport = vport; | 445 | OVS_CB(skb)->input_vport = vport; |
446 | OVS_CB(skb)->mru = 0; | 446 | OVS_CB(skb)->mru = 0; |
447 | OVS_CB(skb)->cutlen = 0; | ||
447 | if (unlikely(dev_net(skb->dev) != ovs_dp_get_net(vport->dp))) { | 448 | if (unlikely(dev_net(skb->dev) != ovs_dp_get_net(vport->dp))) { |
448 | u32 mark; | 449 | u32 mark; |
449 | 450 | ||