diff options
-rw-r--r-- | net/openvswitch/actions.c | 3 | ||||
-rw-r--r-- | net/openvswitch/datapath.c | 45 | ||||
-rw-r--r-- | net/openvswitch/datapath.h | 12 |
3 files changed, 32 insertions, 28 deletions
diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c index d4c2f735d999..10c94ac969f4 100644 --- a/net/openvswitch/actions.c +++ b/net/openvswitch/actions.c | |||
@@ -624,7 +624,6 @@ static int output_userspace(struct datapath *dp, struct sk_buff *skb, | |||
624 | int rem; | 624 | int rem; |
625 | 625 | ||
626 | upcall.cmd = OVS_PACKET_CMD_ACTION; | 626 | upcall.cmd = OVS_PACKET_CMD_ACTION; |
627 | upcall.key = key; | ||
628 | upcall.userdata = NULL; | 627 | upcall.userdata = NULL; |
629 | upcall.portid = 0; | 628 | upcall.portid = 0; |
630 | upcall.egress_tun_info = NULL; | 629 | upcall.egress_tun_info = NULL; |
@@ -659,7 +658,7 @@ static int output_userspace(struct datapath *dp, struct sk_buff *skb, | |||
659 | } /* End of switch. */ | 658 | } /* End of switch. */ |
660 | } | 659 | } |
661 | 660 | ||
662 | return ovs_dp_upcall(dp, skb, &upcall); | 661 | return ovs_dp_upcall(dp, skb, key, &upcall); |
663 | } | 662 | } |
664 | 663 | ||
665 | static int sample(struct datapath *dp, struct sk_buff *skb, | 664 | static int sample(struct datapath *dp, struct sk_buff *skb, |
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c index c2ac340e19fb..7146b38a954e 100644 --- a/net/openvswitch/datapath.c +++ b/net/openvswitch/datapath.c | |||
@@ -136,8 +136,10 @@ EXPORT_SYMBOL_GPL(lockdep_ovsl_is_held); | |||
136 | 136 | ||
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 dp_upcall_info *); | 140 | const struct dp_upcall_info *); |
140 | static int queue_userspace_packet(struct datapath *dp, struct sk_buff *, | 141 | static int queue_userspace_packet(struct datapath *dp, struct sk_buff *, |
142 | const struct sw_flow_key *, | ||
141 | const struct dp_upcall_info *); | 143 | const struct dp_upcall_info *); |
142 | 144 | ||
143 | /* Must be called with rcu_read_lock. */ | 145 | /* Must be called with rcu_read_lock. */ |
@@ -271,11 +273,10 @@ void ovs_dp_process_packet(struct sk_buff *skb, struct sw_flow_key *key) | |||
271 | int error; | 273 | int error; |
272 | 274 | ||
273 | upcall.cmd = OVS_PACKET_CMD_MISS; | 275 | upcall.cmd = OVS_PACKET_CMD_MISS; |
274 | upcall.key = key; | ||
275 | upcall.userdata = NULL; | 276 | upcall.userdata = NULL; |
276 | upcall.portid = ovs_vport_find_upcall_portid(p, skb); | 277 | upcall.portid = ovs_vport_find_upcall_portid(p, skb); |
277 | upcall.egress_tun_info = NULL; | 278 | upcall.egress_tun_info = NULL; |
278 | error = ovs_dp_upcall(dp, skb, &upcall); | 279 | error = ovs_dp_upcall(dp, skb, key, &upcall); |
279 | if (unlikely(error)) | 280 | if (unlikely(error)) |
280 | kfree_skb(skb); | 281 | kfree_skb(skb); |
281 | else | 282 | else |
@@ -299,6 +300,7 @@ out: | |||
299 | } | 300 | } |
300 | 301 | ||
301 | int ovs_dp_upcall(struct datapath *dp, struct sk_buff *skb, | 302 | int ovs_dp_upcall(struct datapath *dp, struct sk_buff *skb, |
303 | const struct sw_flow_key *key, | ||
302 | const struct dp_upcall_info *upcall_info) | 304 | const struct dp_upcall_info *upcall_info) |
303 | { | 305 | { |
304 | struct dp_stats_percpu *stats; | 306 | struct dp_stats_percpu *stats; |
@@ -310,9 +312,9 @@ int ovs_dp_upcall(struct datapath *dp, struct sk_buff *skb, | |||
310 | } | 312 | } |
311 | 313 | ||
312 | if (!skb_is_gso(skb)) | 314 | if (!skb_is_gso(skb)) |
313 | err = queue_userspace_packet(dp, skb, upcall_info); | 315 | err = queue_userspace_packet(dp, skb, key, upcall_info); |
314 | else | 316 | else |
315 | err = queue_gso_packets(dp, skb, upcall_info); | 317 | err = queue_gso_packets(dp, skb, key, upcall_info); |
316 | if (err) | 318 | if (err) |
317 | goto err; | 319 | goto err; |
318 | 320 | ||
@@ -329,39 +331,43 @@ err: | |||
329 | } | 331 | } |
330 | 332 | ||
331 | static int queue_gso_packets(struct datapath *dp, struct sk_buff *skb, | 333 | static int queue_gso_packets(struct datapath *dp, struct sk_buff *skb, |
334 | const struct sw_flow_key *key, | ||
332 | const struct dp_upcall_info *upcall_info) | 335 | const struct dp_upcall_info *upcall_info) |
333 | { | 336 | { |
334 | unsigned short gso_type = skb_shinfo(skb)->gso_type; | 337 | unsigned short gso_type = skb_shinfo(skb)->gso_type; |
335 | struct dp_upcall_info later_info; | ||
336 | struct sw_flow_key later_key; | 338 | struct sw_flow_key later_key; |
337 | struct sk_buff *segs, *nskb; | 339 | struct sk_buff *segs, *nskb; |
340 | struct ovs_skb_cb ovs_cb; | ||
338 | int err; | 341 | int err; |
339 | 342 | ||
343 | ovs_cb = *OVS_CB(skb); | ||
340 | segs = __skb_gso_segment(skb, NETIF_F_SG, false); | 344 | segs = __skb_gso_segment(skb, NETIF_F_SG, false); |
345 | *OVS_CB(skb) = ovs_cb; | ||
341 | if (IS_ERR(segs)) | 346 | if (IS_ERR(segs)) |
342 | return PTR_ERR(segs); | 347 | return PTR_ERR(segs); |
343 | if (segs == NULL) | 348 | if (segs == NULL) |
344 | return -EINVAL; | 349 | return -EINVAL; |
345 | 350 | ||
351 | if (gso_type & SKB_GSO_UDP) { | ||
352 | /* The initial flow key extracted by ovs_flow_key_extract() | ||
353 | * in this case is for a first fragment, so we need to | ||
354 | * properly mark later fragments. | ||
355 | */ | ||
356 | later_key = *key; | ||
357 | later_key.ip.frag = OVS_FRAG_TYPE_LATER; | ||
358 | } | ||
359 | |||
346 | /* Queue all of the segments. */ | 360 | /* Queue all of the segments. */ |
347 | skb = segs; | 361 | skb = segs; |
348 | do { | 362 | do { |
349 | err = queue_userspace_packet(dp, skb, upcall_info); | 363 | *OVS_CB(skb) = ovs_cb; |
364 | if (gso_type & SKB_GSO_UDP && skb != segs) | ||
365 | key = &later_key; | ||
366 | |||
367 | err = queue_userspace_packet(dp, skb, key, upcall_info); | ||
350 | if (err) | 368 | if (err) |
351 | break; | 369 | break; |
352 | 370 | ||
353 | if (skb == segs && gso_type & SKB_GSO_UDP) { | ||
354 | /* The initial flow key extracted by ovs_flow_extract() | ||
355 | * in this case is for a first fragment, so we need to | ||
356 | * properly mark later fragments. | ||
357 | */ | ||
358 | later_key = *upcall_info->key; | ||
359 | later_key.ip.frag = OVS_FRAG_TYPE_LATER; | ||
360 | |||
361 | later_info = *upcall_info; | ||
362 | later_info.key = &later_key; | ||
363 | upcall_info = &later_info; | ||
364 | } | ||
365 | } while ((skb = skb->next)); | 371 | } while ((skb = skb->next)); |
366 | 372 | ||
367 | /* Free all of the segments. */ | 373 | /* Free all of the segments. */ |
@@ -395,6 +401,7 @@ static size_t upcall_msg_size(const struct dp_upcall_info *upcall_info, | |||
395 | } | 401 | } |
396 | 402 | ||
397 | static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb, | 403 | static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb, |
404 | const struct sw_flow_key *key, | ||
398 | const struct dp_upcall_info *upcall_info) | 405 | const struct dp_upcall_info *upcall_info) |
399 | { | 406 | { |
400 | struct ovs_header *upcall; | 407 | struct ovs_header *upcall; |
@@ -457,7 +464,7 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb, | |||
457 | upcall->dp_ifindex = dp_ifindex; | 464 | upcall->dp_ifindex = dp_ifindex; |
458 | 465 | ||
459 | nla = nla_nest_start(user_skb, OVS_PACKET_ATTR_KEY); | 466 | nla = nla_nest_start(user_skb, OVS_PACKET_ATTR_KEY); |
460 | err = ovs_nla_put_flow(upcall_info->key, upcall_info->key, user_skb); | 467 | err = ovs_nla_put_flow(key, key, user_skb); |
461 | BUG_ON(err); | 468 | BUG_ON(err); |
462 | nla_nest_end(user_skb, nla); | 469 | nla_nest_end(user_skb, nla); |
463 | 470 | ||
diff --git a/net/openvswitch/datapath.h b/net/openvswitch/datapath.h index 2bc577bf9b31..8de9f7e20ae9 100644 --- a/net/openvswitch/datapath.h +++ b/net/openvswitch/datapath.h | |||
@@ -108,20 +108,18 @@ struct ovs_skb_cb { | |||
108 | /** | 108 | /** |
109 | * struct dp_upcall - metadata to include with a packet to send to userspace | 109 | * struct dp_upcall - metadata to include with a packet to send to userspace |
110 | * @cmd: One of %OVS_PACKET_CMD_*. | 110 | * @cmd: One of %OVS_PACKET_CMD_*. |
111 | * @key: Becomes %OVS_PACKET_ATTR_KEY. Must be nonnull. | ||
112 | * @userdata: If nonnull, its variable-length value is passed to userspace as | 111 | * @userdata: If nonnull, its variable-length value is passed to userspace as |
113 | * %OVS_PACKET_ATTR_USERDATA. | 112 | * %OVS_PACKET_ATTR_USERDATA. |
114 | * @pid: Netlink PID to which packet should be sent. If @pid is 0 then no | 113 | * @portid: Netlink portid to which packet should be sent. If @portid is 0 |
115 | * packet is sent and the packet is accounted in the datapath's @n_lost | 114 | * then no packet is sent and the packet is accounted in the datapath's @n_lost |
116 | * counter. | 115 | * counter. |
117 | * @egress_tun_info: If nonnull, becomes %OVS_PACKET_ATTR_EGRESS_TUN_KEY. | 116 | * @egress_tun_info: If nonnull, becomes %OVS_PACKET_ATTR_EGRESS_TUN_KEY. |
118 | */ | 117 | */ |
119 | struct dp_upcall_info { | 118 | struct dp_upcall_info { |
120 | u8 cmd; | 119 | const struct ovs_tunnel_info *egress_tun_info; |
121 | const struct sw_flow_key *key; | ||
122 | const struct nlattr *userdata; | 120 | const struct nlattr *userdata; |
123 | u32 portid; | 121 | u32 portid; |
124 | const struct ovs_tunnel_info *egress_tun_info; | 122 | u8 cmd; |
125 | }; | 123 | }; |
126 | 124 | ||
127 | /** | 125 | /** |
@@ -187,7 +185,7 @@ extern struct genl_family dp_vport_genl_family; | |||
187 | void ovs_dp_process_packet(struct sk_buff *skb, struct sw_flow_key *key); | 185 | void ovs_dp_process_packet(struct sk_buff *skb, struct sw_flow_key *key); |
188 | void ovs_dp_detach_port(struct vport *); | 186 | void ovs_dp_detach_port(struct vport *); |
189 | int ovs_dp_upcall(struct datapath *, struct sk_buff *, | 187 | int ovs_dp_upcall(struct datapath *, struct sk_buff *, |
190 | const struct dp_upcall_info *); | 188 | const struct sw_flow_key *, const struct dp_upcall_info *); |
191 | 189 | ||
192 | const char *ovs_dp_name(const struct datapath *dp); | 190 | const char *ovs_dp_name(const struct datapath *dp); |
193 | struct sk_buff *ovs_vport_cmd_build_info(struct vport *, u32 pid, u32 seq, | 191 | struct sk_buff *ovs_vport_cmd_build_info(struct vport *, u32 pid, u32 seq, |