aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/openvswitch/actions.c3
-rw-r--r--net/openvswitch/datapath.c45
-rw-r--r--net/openvswitch/datapath.h12
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
665static int sample(struct datapath *dp, struct sk_buff *skb, 664static 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
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 dp_upcall_info *); 140 const struct dp_upcall_info *);
140static int queue_userspace_packet(struct datapath *dp, struct sk_buff *, 141static 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
301int ovs_dp_upcall(struct datapath *dp, struct sk_buff *skb, 302int 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
331static int queue_gso_packets(struct datapath *dp, struct sk_buff *skb, 333static 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
397static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb, 403static 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 */
119struct dp_upcall_info { 118struct 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;
187void ovs_dp_process_packet(struct sk_buff *skb, struct sw_flow_key *key); 185void ovs_dp_process_packet(struct sk_buff *skb, struct sw_flow_key *key);
188void ovs_dp_detach_port(struct vport *); 186void ovs_dp_detach_port(struct vport *);
189int ovs_dp_upcall(struct datapath *, struct sk_buff *, 187int 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
192const char *ovs_dp_name(const struct datapath *dp); 190const char *ovs_dp_name(const struct datapath *dp);
193struct sk_buff *ovs_vport_cmd_build_info(struct vport *, u32 pid, u32 seq, 191struct sk_buff *ovs_vport_cmd_build_info(struct vport *, u32 pid, u32 seq,