aboutsummaryrefslogtreecommitdiffstats
path: root/net/openvswitch
diff options
context:
space:
mode:
authorWilliam Tu <u9012063@gmail.com>2016-06-10 14:49:33 -0400
committerDavid S. Miller <davem@davemloft.net>2016-06-10 20:58:03 -0400
commitf2a4d086ed4c588d32fe9b7aa67fead7280e7bf1 (patch)
tree7824d6446b4fd259cc7430641fd27475445361ba /net/openvswitch
parent1578b0a5e92825334760741e5c166b8873886f1b (diff)
openvswitch: Add packet truncation support.
The patch adds a new OVS action, OVS_ACTION_ATTR_TRUNC, in order to truncate packets. A 'max_len' is added for setting up the maximum packet size, and a 'cutlen' field is to record the number of bytes to trim the packet when the packet is outputting to a port, or when the packet is sent to userspace. Signed-off-by: William Tu <u9012063@gmail.com> Cc: Pravin Shelar <pshelar@nicira.com> Acked-by: Pravin B Shelar <pshelar@ovn.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/openvswitch')
-rw-r--r--net/openvswitch/actions.c40
-rw-r--r--net/openvswitch/datapath.c29
-rw-r--r--net/openvswitch/datapath.h5
-rw-r--r--net/openvswitch/flow_netlink.c9
-rw-r--r--net/openvswitch/vport.c1
5 files changed, 67 insertions, 17 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
776static int output_userspace(struct datapath *dp, struct sk_buff *skb, 784static 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
828static int sample(struct datapath *dp, struct sk_buff *skb, 837static 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/datapath.c b/net/openvswitch/datapath.c
index 856bd8dba676..673934295333 100644
--- a/net/openvswitch/datapath.c
+++ b/net/openvswitch/datapath.c
@@ -137,10 +137,12 @@ EXPORT_SYMBOL_GPL(lockdep_ovsl_is_held);
137static struct vport *new_vport(const struct vport_parms *); 137static struct vport *new_vport(const struct vport_parms *);
138static int queue_gso_packets(struct datapath *dp, struct sk_buff *, 138static 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);
141static int queue_userspace_packet(struct datapath *dp, struct sk_buff *, 142static 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. */
146static struct datapath *get_dp_rcu(struct net *net, int dp_ifindex) 148static 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
301int ovs_dp_upcall(struct datapath *dp, struct sk_buff *skb, 303int 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
332static int queue_gso_packets(struct datapath *dp, struct sk_buff *skb, 335static 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
@@ -416,7 +420,8 @@ static void pad_packet(struct datapath *dp, struct sk_buff *skb)
416 420
417static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb, 421static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
418 const struct sw_flow_key *key, 422 const struct sw_flow_key *key,
419 const struct dp_upcall_info *upcall_info) 423 const struct dp_upcall_info *upcall_info,
424 uint32_t cutlen)
420{ 425{
421 struct ovs_header *upcall; 426 struct ovs_header *upcall;
422 struct sk_buff *nskb = NULL; 427 struct sk_buff *nskb = NULL;
@@ -461,7 +466,7 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
461 else 466 else
462 hlen = skb->len; 467 hlen = skb->len;
463 468
464 len = upcall_msg_size(upcall_info, hlen); 469 len = upcall_msg_size(upcall_info, hlen - cutlen);
465 user_skb = genlmsg_new(len, GFP_ATOMIC); 470 user_skb = genlmsg_new(len, GFP_ATOMIC);
466 if (!user_skb) { 471 if (!user_skb) {
467 err = -ENOMEM; 472 err = -ENOMEM;
@@ -515,9 +520,9 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
515 err = -ENOBUFS; 520 err = -ENOBUFS;
516 goto out; 521 goto out;
517 } 522 }
518 nla->nla_len = nla_attr_size(skb->len); 523 nla->nla_len = nla_attr_size(skb->len - cutlen);
519 524
520 err = skb_zerocopy(user_skb, skb, skb->len, hlen); 525 err = skb_zerocopy(user_skb, skb, skb->len - cutlen, hlen);
521 if (err) 526 if (err)
522 goto out; 527 goto out;
523 528
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 */
105struct ovs_skb_cb { 106struct 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;
194void ovs_dp_process_packet(struct sk_buff *skb, struct sw_flow_key *key); 196void ovs_dp_process_packet(struct sk_buff *skb, struct sw_flow_key *key);
195void ovs_dp_detach_port(struct vport *); 197void ovs_dp_detach_port(struct vport *);
196int ovs_dp_upcall(struct datapath *, struct sk_buff *, 198int 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
199const char *ovs_dp_name(const struct datapath *dp); 202const char *ovs_dp_name(const struct datapath *dp);
200struct sk_buff *ovs_vport_cmd_build_info(struct vport *, u32 pid, u32 seq, 203struct 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.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