forked from mirrors/linux
		
	net: openvswitch: Add support to count upcall packets
Add support to count upall packets, when kmod of openvswitch upcall to count the number of packets for upcall succeed and failed, which is a better way to see how many packets upcalled on every interfaces. Signed-off-by: wangchuanlei <wangchuanlei@inspur.com> Acked-by: Eelco Chaudron <echaudro@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									e47877c7aa
								
							
						
					
					
						commit
						1933ea365a
					
				
					 4 changed files with 121 additions and 0 deletions
				
			
		|  | @ -277,11 +277,25 @@ enum ovs_vport_attr { | |||
| 	OVS_VPORT_ATTR_PAD, | ||||
| 	OVS_VPORT_ATTR_IFINDEX, | ||||
| 	OVS_VPORT_ATTR_NETNSID, | ||||
| 	OVS_VPORT_ATTR_UPCALL_STATS, | ||||
| 	__OVS_VPORT_ATTR_MAX | ||||
| }; | ||||
| 
 | ||||
| #define OVS_VPORT_ATTR_MAX (__OVS_VPORT_ATTR_MAX - 1) | ||||
| 
 | ||||
| /**
 | ||||
|  * enum ovs_vport_upcall_attr - attributes for %OVS_VPORT_UPCALL* commands | ||||
|  * @OVS_VPORT_UPCALL_SUCCESS: 64-bit upcall success packets. | ||||
|  * @OVS_VPORT_UPCALL_FAIL: 64-bit upcall fail packets. | ||||
|  */ | ||||
| enum ovs_vport_upcall_attr { | ||||
| 	OVS_VPORT_UPCALL_ATTR_SUCCESS, | ||||
| 	OVS_VPORT_UPCALL_ATTR_FAIL, | ||||
| 	__OVS_VPORT_UPCALL_ATTR_MAX | ||||
| }; | ||||
| 
 | ||||
| #define OVS_VPORT_UPCALL_ATTR_MAX (__OVS_VPORT_UPCALL_ATTR_MAX - 1) | ||||
| 
 | ||||
| enum { | ||||
| 	OVS_VXLAN_EXT_UNSPEC, | ||||
| 	OVS_VXLAN_EXT_GBP,	/* Flag or __u32 */ | ||||
|  |  | |||
|  | @ -209,6 +209,26 @@ static struct vport *new_vport(const struct vport_parms *parms) | |||
| 	return vport; | ||||
| } | ||||
| 
 | ||||
| static void ovs_vport_update_upcall_stats(struct sk_buff *skb, | ||||
| 					  const struct dp_upcall_info *upcall_info, | ||||
| 					  bool upcall_result) | ||||
| { | ||||
| 	struct vport *p = OVS_CB(skb)->input_vport; | ||||
| 	struct vport_upcall_stats_percpu *stats; | ||||
| 
 | ||||
| 	if (upcall_info->cmd != OVS_PACKET_CMD_MISS && | ||||
| 	    upcall_info->cmd != OVS_PACKET_CMD_ACTION) | ||||
| 		return; | ||||
| 
 | ||||
| 	stats = this_cpu_ptr(p->upcall_stats); | ||||
| 	u64_stats_update_begin(&stats->syncp); | ||||
| 	if (upcall_result) | ||||
| 		u64_stats_inc(&stats->n_success); | ||||
| 	else | ||||
| 		u64_stats_inc(&stats->n_fail); | ||||
| 	u64_stats_update_end(&stats->syncp); | ||||
| } | ||||
| 
 | ||||
| void ovs_dp_detach_port(struct vport *p) | ||||
| { | ||||
| 	ASSERT_OVSL(); | ||||
|  | @ -216,6 +236,9 @@ void ovs_dp_detach_port(struct vport *p) | |||
| 	/* First drop references to device. */ | ||||
| 	hlist_del_rcu(&p->dp_hash_node); | ||||
| 
 | ||||
| 	/* Free percpu memory */ | ||||
| 	free_percpu(p->upcall_stats); | ||||
| 
 | ||||
| 	/* Then destroy it. */ | ||||
| 	ovs_vport_del(p); | ||||
| } | ||||
|  | @ -305,6 +328,8 @@ int ovs_dp_upcall(struct datapath *dp, struct sk_buff *skb, | |||
| 		err = queue_userspace_packet(dp, skb, key, upcall_info, cutlen); | ||||
| 	else | ||||
| 		err = queue_gso_packets(dp, skb, key, upcall_info, cutlen); | ||||
| 
 | ||||
| 	ovs_vport_update_upcall_stats(skb, upcall_info, !err); | ||||
| 	if (err) | ||||
| 		goto err; | ||||
| 
 | ||||
|  | @ -1826,6 +1851,12 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info) | |||
| 		goto err_destroy_portids; | ||||
| 	} | ||||
| 
 | ||||
| 	vport->upcall_stats = netdev_alloc_pcpu_stats(struct vport_upcall_stats_percpu); | ||||
| 	if (!vport->upcall_stats) { | ||||
| 		err = -ENOMEM; | ||||
| 		goto err_destroy_portids; | ||||
| 	} | ||||
| 
 | ||||
| 	err = ovs_dp_cmd_fill_info(dp, reply, info->snd_portid, | ||||
| 				   info->snd_seq, 0, OVS_DP_CMD_NEW); | ||||
| 	BUG_ON(err < 0); | ||||
|  | @ -2098,6 +2129,9 @@ static int ovs_vport_cmd_fill_info(struct vport *vport, struct sk_buff *skb, | |||
| 			  OVS_VPORT_ATTR_PAD)) | ||||
| 		goto nla_put_failure; | ||||
| 
 | ||||
| 	if (ovs_vport_get_upcall_stats(vport, skb)) | ||||
| 		goto nla_put_failure; | ||||
| 
 | ||||
| 	if (ovs_vport_get_upcall_portids(vport, skb)) | ||||
| 		goto nla_put_failure; | ||||
| 
 | ||||
|  | @ -2279,6 +2313,12 @@ static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info) | |||
| 		goto exit_unlock_free; | ||||
| 	} | ||||
| 
 | ||||
| 	vport->upcall_stats = netdev_alloc_pcpu_stats(struct vport_upcall_stats_percpu); | ||||
| 	if (!vport->upcall_stats) { | ||||
| 		err = -ENOMEM; | ||||
| 		goto exit_unlock_free; | ||||
| 	} | ||||
| 
 | ||||
| 	err = ovs_vport_cmd_fill_info(vport, reply, genl_info_net(info), | ||||
| 				      info->snd_portid, info->snd_seq, 0, | ||||
| 				      OVS_VPORT_CMD_NEW, GFP_KERNEL); | ||||
|  | @ -2508,6 +2548,7 @@ static const struct nla_policy vport_policy[OVS_VPORT_ATTR_MAX + 1] = { | |||
| 	[OVS_VPORT_ATTR_OPTIONS] = { .type = NLA_NESTED }, | ||||
| 	[OVS_VPORT_ATTR_IFINDEX] = { .type = NLA_U32 }, | ||||
| 	[OVS_VPORT_ATTR_NETNSID] = { .type = NLA_S32 }, | ||||
| 	[OVS_VPORT_ATTR_UPCALL_STATS] = { .type = NLA_NESTED }, | ||||
| }; | ||||
| 
 | ||||
| static const struct genl_small_ops dp_vport_genl_ops[] = { | ||||
|  |  | |||
|  | @ -284,6 +284,56 @@ void ovs_vport_get_stats(struct vport *vport, struct ovs_vport_stats *stats) | |||
| 	stats->tx_packets = dev_stats->tx_packets; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  *	ovs_vport_get_upcall_stats - retrieve upcall stats | ||||
|  * | ||||
|  * @vport: vport from which to retrieve the stats. | ||||
|  * @skb: sk_buff where upcall stats should be appended. | ||||
|  * | ||||
|  * Retrieves upcall stats for the given device. | ||||
|  * | ||||
|  * Must be called with ovs_mutex or rcu_read_lock. | ||||
|  */ | ||||
| int ovs_vport_get_upcall_stats(struct vport *vport, struct sk_buff *skb) | ||||
| { | ||||
| 	struct nlattr *nla; | ||||
| 	int i; | ||||
| 
 | ||||
| 	__u64 tx_success = 0; | ||||
| 	__u64 tx_fail = 0; | ||||
| 
 | ||||
| 	for_each_possible_cpu(i) { | ||||
| 		const struct vport_upcall_stats_percpu *stats; | ||||
| 		unsigned int start; | ||||
| 
 | ||||
| 		stats = per_cpu_ptr(vport->upcall_stats, i); | ||||
| 		do { | ||||
| 			start = u64_stats_fetch_begin(&stats->syncp); | ||||
| 			tx_success += u64_stats_read(&stats->n_success); | ||||
| 			tx_fail += u64_stats_read(&stats->n_fail); | ||||
| 		} while (u64_stats_fetch_retry(&stats->syncp, start)); | ||||
| 	} | ||||
| 
 | ||||
| 	nla = nla_nest_start_noflag(skb, OVS_VPORT_ATTR_UPCALL_STATS); | ||||
| 	if (!nla) | ||||
| 		return -EMSGSIZE; | ||||
| 
 | ||||
| 	if (nla_put_u64_64bit(skb, OVS_VPORT_UPCALL_ATTR_SUCCESS, tx_success, | ||||
| 			      OVS_VPORT_ATTR_PAD)) { | ||||
| 		nla_nest_cancel(skb, nla); | ||||
| 		return -EMSGSIZE; | ||||
| 	} | ||||
| 
 | ||||
| 	if (nla_put_u64_64bit(skb, OVS_VPORT_UPCALL_ATTR_FAIL, tx_fail, | ||||
| 			      OVS_VPORT_ATTR_PAD)) { | ||||
| 		nla_nest_cancel(skb, nla); | ||||
| 		return -EMSGSIZE; | ||||
| 	} | ||||
| 	nla_nest_end(skb, nla); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  *	ovs_vport_get_options - retrieve device options | ||||
|  * | ||||
|  |  | |||
|  | @ -32,6 +32,8 @@ struct vport *ovs_vport_locate(const struct net *net, const char *name); | |||
| 
 | ||||
| void ovs_vport_get_stats(struct vport *, struct ovs_vport_stats *); | ||||
| 
 | ||||
| int ovs_vport_get_upcall_stats(struct vport *vport, struct sk_buff *skb); | ||||
| 
 | ||||
| int ovs_vport_set_options(struct vport *, struct nlattr *options); | ||||
| int ovs_vport_get_options(const struct vport *, struct sk_buff *); | ||||
| 
 | ||||
|  | @ -65,6 +67,7 @@ struct vport_portids { | |||
|  * @hash_node: Element in @dev_table hash table in vport.c. | ||||
|  * @dp_hash_node: Element in @datapath->ports hash table in datapath.c. | ||||
|  * @ops: Class structure. | ||||
|  * @upcall_stats: Upcall stats of every ports. | ||||
|  * @detach_list: list used for detaching vport in net-exit call. | ||||
|  * @rcu: RCU callback head for deferred destruction. | ||||
|  */ | ||||
|  | @ -78,6 +81,7 @@ struct vport { | |||
| 	struct hlist_node hash_node; | ||||
| 	struct hlist_node dp_hash_node; | ||||
| 	const struct vport_ops *ops; | ||||
| 	struct vport_upcall_stats_percpu __percpu *upcall_stats; | ||||
| 
 | ||||
| 	struct list_head detach_list; | ||||
| 	struct rcu_head rcu; | ||||
|  | @ -137,6 +141,18 @@ struct vport_ops { | |||
| 	struct list_head list; | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  * struct vport_upcall_stats_percpu - per-cpu packet upcall statistics for | ||||
|  * a given vport. | ||||
|  * @n_success: Number of packets that upcall to userspace succeed. | ||||
|  * @n_fail:    Number of packets that upcall to userspace failed. | ||||
|  */ | ||||
| struct vport_upcall_stats_percpu { | ||||
| 	struct u64_stats_sync syncp; | ||||
| 	u64_stats_t n_success; | ||||
| 	u64_stats_t n_fail; | ||||
| }; | ||||
| 
 | ||||
| struct vport *ovs_vport_alloc(int priv_size, const struct vport_ops *, | ||||
| 			      const struct vport_parms *); | ||||
| void ovs_vport_free(struct vport *); | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 wangchuanlei
						wangchuanlei