Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os 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>

authored by

wangchuanlei and committed by
David S. Miller
1933ea36 e47877c7

+121
+14
include/uapi/linux/openvswitch.h
··· 277 277 OVS_VPORT_ATTR_PAD, 278 278 OVS_VPORT_ATTR_IFINDEX, 279 279 OVS_VPORT_ATTR_NETNSID, 280 + OVS_VPORT_ATTR_UPCALL_STATS, 280 281 __OVS_VPORT_ATTR_MAX 281 282 }; 282 283 283 284 #define OVS_VPORT_ATTR_MAX (__OVS_VPORT_ATTR_MAX - 1) 285 + 286 + /** 287 + * enum ovs_vport_upcall_attr - attributes for %OVS_VPORT_UPCALL* commands 288 + * @OVS_VPORT_UPCALL_SUCCESS: 64-bit upcall success packets. 289 + * @OVS_VPORT_UPCALL_FAIL: 64-bit upcall fail packets. 290 + */ 291 + enum ovs_vport_upcall_attr { 292 + OVS_VPORT_UPCALL_ATTR_SUCCESS, 293 + OVS_VPORT_UPCALL_ATTR_FAIL, 294 + __OVS_VPORT_UPCALL_ATTR_MAX 295 + }; 296 + 297 + #define OVS_VPORT_UPCALL_ATTR_MAX (__OVS_VPORT_UPCALL_ATTR_MAX - 1) 284 298 285 299 enum { 286 300 OVS_VXLAN_EXT_UNSPEC,
+41
net/openvswitch/datapath.c
··· 209 209 return vport; 210 210 } 211 211 212 + static void ovs_vport_update_upcall_stats(struct sk_buff *skb, 213 + const struct dp_upcall_info *upcall_info, 214 + bool upcall_result) 215 + { 216 + struct vport *p = OVS_CB(skb)->input_vport; 217 + struct vport_upcall_stats_percpu *stats; 218 + 219 + if (upcall_info->cmd != OVS_PACKET_CMD_MISS && 220 + upcall_info->cmd != OVS_PACKET_CMD_ACTION) 221 + return; 222 + 223 + stats = this_cpu_ptr(p->upcall_stats); 224 + u64_stats_update_begin(&stats->syncp); 225 + if (upcall_result) 226 + u64_stats_inc(&stats->n_success); 227 + else 228 + u64_stats_inc(&stats->n_fail); 229 + u64_stats_update_end(&stats->syncp); 230 + } 231 + 212 232 void ovs_dp_detach_port(struct vport *p) 213 233 { 214 234 ASSERT_OVSL(); 215 235 216 236 /* First drop references to device. */ 217 237 hlist_del_rcu(&p->dp_hash_node); 238 + 239 + /* Free percpu memory */ 240 + free_percpu(p->upcall_stats); 218 241 219 242 /* Then destroy it. */ 220 243 ovs_vport_del(p); ··· 328 305 err = queue_userspace_packet(dp, skb, key, upcall_info, cutlen); 329 306 else 330 307 err = queue_gso_packets(dp, skb, key, upcall_info, cutlen); 308 + 309 + ovs_vport_update_upcall_stats(skb, upcall_info, !err); 331 310 if (err) 332 311 goto err; 333 312 ··· 1851 1826 goto err_destroy_portids; 1852 1827 } 1853 1828 1829 + vport->upcall_stats = netdev_alloc_pcpu_stats(struct vport_upcall_stats_percpu); 1830 + if (!vport->upcall_stats) { 1831 + err = -ENOMEM; 1832 + goto err_destroy_portids; 1833 + } 1834 + 1854 1835 err = ovs_dp_cmd_fill_info(dp, reply, info->snd_portid, 1855 1836 info->snd_seq, 0, OVS_DP_CMD_NEW); 1856 1837 BUG_ON(err < 0); ··· 2129 2098 OVS_VPORT_ATTR_PAD)) 2130 2099 goto nla_put_failure; 2131 2100 2101 + if (ovs_vport_get_upcall_stats(vport, skb)) 2102 + goto nla_put_failure; 2103 + 2132 2104 if (ovs_vport_get_upcall_portids(vport, skb)) 2133 2105 goto nla_put_failure; 2134 2106 ··· 2310 2276 if (IS_ERR(vport)) { 2311 2277 if (err == -EAGAIN) 2312 2278 goto restart; 2279 + goto exit_unlock_free; 2280 + } 2281 + 2282 + vport->upcall_stats = netdev_alloc_pcpu_stats(struct vport_upcall_stats_percpu); 2283 + if (!vport->upcall_stats) { 2284 + err = -ENOMEM; 2313 2285 goto exit_unlock_free; 2314 2286 } 2315 2287 ··· 2548 2508 [OVS_VPORT_ATTR_OPTIONS] = { .type = NLA_NESTED }, 2549 2509 [OVS_VPORT_ATTR_IFINDEX] = { .type = NLA_U32 }, 2550 2510 [OVS_VPORT_ATTR_NETNSID] = { .type = NLA_S32 }, 2511 + [OVS_VPORT_ATTR_UPCALL_STATS] = { .type = NLA_NESTED }, 2551 2512 }; 2552 2513 2553 2514 static const struct genl_small_ops dp_vport_genl_ops[] = {
+50
net/openvswitch/vport.c
··· 285 285 } 286 286 287 287 /** 288 + * ovs_vport_get_upcall_stats - retrieve upcall stats 289 + * 290 + * @vport: vport from which to retrieve the stats. 291 + * @skb: sk_buff where upcall stats should be appended. 292 + * 293 + * Retrieves upcall stats for the given device. 294 + * 295 + * Must be called with ovs_mutex or rcu_read_lock. 296 + */ 297 + int ovs_vport_get_upcall_stats(struct vport *vport, struct sk_buff *skb) 298 + { 299 + struct nlattr *nla; 300 + int i; 301 + 302 + __u64 tx_success = 0; 303 + __u64 tx_fail = 0; 304 + 305 + for_each_possible_cpu(i) { 306 + const struct vport_upcall_stats_percpu *stats; 307 + unsigned int start; 308 + 309 + stats = per_cpu_ptr(vport->upcall_stats, i); 310 + do { 311 + start = u64_stats_fetch_begin(&stats->syncp); 312 + tx_success += u64_stats_read(&stats->n_success); 313 + tx_fail += u64_stats_read(&stats->n_fail); 314 + } while (u64_stats_fetch_retry(&stats->syncp, start)); 315 + } 316 + 317 + nla = nla_nest_start_noflag(skb, OVS_VPORT_ATTR_UPCALL_STATS); 318 + if (!nla) 319 + return -EMSGSIZE; 320 + 321 + if (nla_put_u64_64bit(skb, OVS_VPORT_UPCALL_ATTR_SUCCESS, tx_success, 322 + OVS_VPORT_ATTR_PAD)) { 323 + nla_nest_cancel(skb, nla); 324 + return -EMSGSIZE; 325 + } 326 + 327 + if (nla_put_u64_64bit(skb, OVS_VPORT_UPCALL_ATTR_FAIL, tx_fail, 328 + OVS_VPORT_ATTR_PAD)) { 329 + nla_nest_cancel(skb, nla); 330 + return -EMSGSIZE; 331 + } 332 + nla_nest_end(skb, nla); 333 + 334 + return 0; 335 + } 336 + 337 + /** 288 338 * ovs_vport_get_options - retrieve device options 289 339 * 290 340 * @vport: vport from which to retrieve the options.
+16
net/openvswitch/vport.h
··· 32 32 33 33 void ovs_vport_get_stats(struct vport *, struct ovs_vport_stats *); 34 34 35 + int ovs_vport_get_upcall_stats(struct vport *vport, struct sk_buff *skb); 36 + 35 37 int ovs_vport_set_options(struct vport *, struct nlattr *options); 36 38 int ovs_vport_get_options(const struct vport *, struct sk_buff *); 37 39 ··· 67 65 * @hash_node: Element in @dev_table hash table in vport.c. 68 66 * @dp_hash_node: Element in @datapath->ports hash table in datapath.c. 69 67 * @ops: Class structure. 68 + * @upcall_stats: Upcall stats of every ports. 70 69 * @detach_list: list used for detaching vport in net-exit call. 71 70 * @rcu: RCU callback head for deferred destruction. 72 71 */ ··· 81 78 struct hlist_node hash_node; 82 79 struct hlist_node dp_hash_node; 83 80 const struct vport_ops *ops; 81 + struct vport_upcall_stats_percpu __percpu *upcall_stats; 84 82 85 83 struct list_head detach_list; 86 84 struct rcu_head rcu; ··· 139 135 int (*send)(struct sk_buff *skb); 140 136 struct module *owner; 141 137 struct list_head list; 138 + }; 139 + 140 + /** 141 + * struct vport_upcall_stats_percpu - per-cpu packet upcall statistics for 142 + * a given vport. 143 + * @n_success: Number of packets that upcall to userspace succeed. 144 + * @n_fail: Number of packets that upcall to userspace failed. 145 + */ 146 + struct vport_upcall_stats_percpu { 147 + struct u64_stats_sync syncp; 148 + u64_stats_t n_success; 149 + u64_stats_t n_fail; 142 150 }; 143 151 144 152 struct vport *ovs_vport_alloc(int priv_size, const struct vport_ops *,