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_PAD, | ||||||
| 	OVS_VPORT_ATTR_IFINDEX, | 	OVS_VPORT_ATTR_IFINDEX, | ||||||
| 	OVS_VPORT_ATTR_NETNSID, | 	OVS_VPORT_ATTR_NETNSID, | ||||||
|  | 	OVS_VPORT_ATTR_UPCALL_STATS, | ||||||
| 	__OVS_VPORT_ATTR_MAX | 	__OVS_VPORT_ATTR_MAX | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| #define OVS_VPORT_ATTR_MAX (__OVS_VPORT_ATTR_MAX - 1) | #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 { | enum { | ||||||
| 	OVS_VXLAN_EXT_UNSPEC, | 	OVS_VXLAN_EXT_UNSPEC, | ||||||
| 	OVS_VXLAN_EXT_GBP,	/* Flag or __u32 */ | 	OVS_VXLAN_EXT_GBP,	/* Flag or __u32 */ | ||||||
|  |  | ||||||
|  | @ -209,6 +209,26 @@ static struct vport *new_vport(const struct vport_parms *parms) | ||||||
| 	return vport; | 	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) | void ovs_dp_detach_port(struct vport *p) | ||||||
| { | { | ||||||
| 	ASSERT_OVSL(); | 	ASSERT_OVSL(); | ||||||
|  | @ -216,6 +236,9 @@ void ovs_dp_detach_port(struct vport *p) | ||||||
| 	/* First drop references to device. */ | 	/* First drop references to device. */ | ||||||
| 	hlist_del_rcu(&p->dp_hash_node); | 	hlist_del_rcu(&p->dp_hash_node); | ||||||
| 
 | 
 | ||||||
|  | 	/* Free percpu memory */ | ||||||
|  | 	free_percpu(p->upcall_stats); | ||||||
|  | 
 | ||||||
| 	/* Then destroy it. */ | 	/* Then destroy it. */ | ||||||
| 	ovs_vport_del(p); | 	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); | 		err = queue_userspace_packet(dp, skb, key, upcall_info, cutlen); | ||||||
| 	else | 	else | ||||||
| 		err = queue_gso_packets(dp, skb, key, upcall_info, cutlen); | 		err = queue_gso_packets(dp, skb, key, upcall_info, cutlen); | ||||||
|  | 
 | ||||||
|  | 	ovs_vport_update_upcall_stats(skb, upcall_info, !err); | ||||||
| 	if (err) | 	if (err) | ||||||
| 		goto 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; | 		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, | 	err = ovs_dp_cmd_fill_info(dp, reply, info->snd_portid, | ||||||
| 				   info->snd_seq, 0, OVS_DP_CMD_NEW); | 				   info->snd_seq, 0, OVS_DP_CMD_NEW); | ||||||
| 	BUG_ON(err < 0); | 	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)) | 			  OVS_VPORT_ATTR_PAD)) | ||||||
| 		goto nla_put_failure; | 		goto nla_put_failure; | ||||||
| 
 | 
 | ||||||
|  | 	if (ovs_vport_get_upcall_stats(vport, skb)) | ||||||
|  | 		goto nla_put_failure; | ||||||
|  | 
 | ||||||
| 	if (ovs_vport_get_upcall_portids(vport, skb)) | 	if (ovs_vport_get_upcall_portids(vport, skb)) | ||||||
| 		goto nla_put_failure; | 		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; | 		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), | 	err = ovs_vport_cmd_fill_info(vport, reply, genl_info_net(info), | ||||||
| 				      info->snd_portid, info->snd_seq, 0, | 				      info->snd_portid, info->snd_seq, 0, | ||||||
| 				      OVS_VPORT_CMD_NEW, GFP_KERNEL); | 				      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_OPTIONS] = { .type = NLA_NESTED }, | ||||||
| 	[OVS_VPORT_ATTR_IFINDEX] = { .type = NLA_U32 }, | 	[OVS_VPORT_ATTR_IFINDEX] = { .type = NLA_U32 }, | ||||||
| 	[OVS_VPORT_ATTR_NETNSID] = { .type = NLA_S32 }, | 	[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[] = { | 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; | 	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 |  *	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 *); | 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_set_options(struct vport *, struct nlattr *options); | ||||||
| int ovs_vport_get_options(const struct vport *, struct sk_buff *); | 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. |  * @hash_node: Element in @dev_table hash table in vport.c. | ||||||
|  * @dp_hash_node: Element in @datapath->ports hash table in datapath.c. |  * @dp_hash_node: Element in @datapath->ports hash table in datapath.c. | ||||||
|  * @ops: Class structure. |  * @ops: Class structure. | ||||||
|  |  * @upcall_stats: Upcall stats of every ports. | ||||||
|  * @detach_list: list used for detaching vport in net-exit call. |  * @detach_list: list used for detaching vport in net-exit call. | ||||||
|  * @rcu: RCU callback head for deferred destruction. |  * @rcu: RCU callback head for deferred destruction. | ||||||
|  */ |  */ | ||||||
|  | @ -78,6 +81,7 @@ struct vport { | ||||||
| 	struct hlist_node hash_node; | 	struct hlist_node hash_node; | ||||||
| 	struct hlist_node dp_hash_node; | 	struct hlist_node dp_hash_node; | ||||||
| 	const struct vport_ops *ops; | 	const struct vport_ops *ops; | ||||||
|  | 	struct vport_upcall_stats_percpu __percpu *upcall_stats; | ||||||
| 
 | 
 | ||||||
| 	struct list_head detach_list; | 	struct list_head detach_list; | ||||||
| 	struct rcu_head rcu; | 	struct rcu_head rcu; | ||||||
|  | @ -137,6 +141,18 @@ struct vport_ops { | ||||||
| 	struct list_head list; | 	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 *, | struct vport *ovs_vport_alloc(int priv_size, const struct vport_ops *, | ||||||
| 			      const struct vport_parms *); | 			      const struct vport_parms *); | ||||||
| void ovs_vport_free(struct vport *); | void ovs_vport_free(struct vport *); | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 wangchuanlei
						wangchuanlei