diff --git a/samples/bpf/xdp_redirect_cpu_kern.c b/samples/bpf/xdp_redirect_cpu_kern.c
index 2baf8db1f7e7..72d322ae295a 100644
--- a/samples/bpf/xdp_redirect_cpu_kern.c
+++ b/samples/bpf/xdp_redirect_cpu_kern.c
@@ -17,11 +17,17 @@
 
 #define MAX_CPUS NR_CPUS
 
+/* Special map type that can XDP_REDIRECT frames to another CPU */
+struct cpu_map_entry {
+	__u32 prog_id;
+	__u32 qsize;
+};
+
 /* Special map type that can XDP_REDIRECT frames to another CPU */
 struct {
 	__uint(type, BPF_MAP_TYPE_CPUMAP);
 	__uint(key_size, sizeof(u32));
-	__uint(value_size, sizeof(u32));
+	__uint(value_size, sizeof(struct cpu_map_entry));
 	__uint(max_entries, MAX_CPUS);
 } cpu_map SEC(".maps");
 
@@ -30,6 +36,9 @@ struct datarec {
 	__u64 processed;
 	__u64 dropped;
 	__u64 issue;
+	__u64 xdp_redirect;
+	__u64 xdp_pass;
+	__u64 xdp_drop;
 };
 
 /* Count RX packets, as XDP bpf_prog doesn't get direct TX-success
@@ -227,6 +236,19 @@ int  xdp_prognum0_no_touch(struct xdp_md *ctx)
 	return bpf_redirect_map(&cpu_map, cpu_dest, 0);
 }
 
+SEC("xdp_cpu_prog_pass")
+int xdp_cpumap_prog_pass(struct xdp_md *ctx)
+{
+	struct datarec *rec;
+	u32 key = 0;
+
+	rec = bpf_map_lookup_elem(&rx_cnt, &key);
+	if (rec)
+		rec->xdp_pass++;
+
+	return XDP_PASS;
+}
+
 SEC("xdp_cpu_map1_touch_data")
 int  xdp_prognum1_touch_data(struct xdp_md *ctx)
 {
diff --git a/samples/bpf/xdp_redirect_cpu_user.c b/samples/bpf/xdp_redirect_cpu_user.c
index f3468168982e..f60875f32cd9 100644
--- a/samples/bpf/xdp_redirect_cpu_user.c
+++ b/samples/bpf/xdp_redirect_cpu_user.c
@@ -30,6 +30,11 @@ static const char *__doc__ =
 
 #include "bpf_util.h"
 
+struct cpu_map_entry {
+	__u32 prog_id;
+	__u32 qsize;
+};
+
 static int ifindex = -1;
 static char ifname_buf[IF_NAMESIZE];
 static char *ifname;
@@ -156,6 +161,9 @@ struct datarec {
 	__u64 processed;
 	__u64 dropped;
 	__u64 issue;
+	__u64 xdp_redirect;
+	__u64 xdp_pass;
+	__u64 xdp_drop;
 };
 struct record {
 	__u64 timestamp;
@@ -175,6 +183,9 @@ static bool map_collect_percpu(int fd, __u32 key, struct record *rec)
 	/* For percpu maps, userspace gets a value per possible CPU */
 	unsigned int nr_cpus = bpf_num_possible_cpus();
 	struct datarec values[nr_cpus];
+	__u64 sum_xdp_redirect = 0;
+	__u64 sum_xdp_pass = 0;
+	__u64 sum_xdp_drop = 0;
 	__u64 sum_processed = 0;
 	__u64 sum_dropped = 0;
 	__u64 sum_issue = 0;
@@ -196,10 +207,19 @@ static bool map_collect_percpu(int fd, __u32 key, struct record *rec)
 		sum_dropped        += values[i].dropped;
 		rec->cpu[i].issue = values[i].issue;
 		sum_issue        += values[i].issue;
+		rec->cpu[i].xdp_pass = values[i].xdp_pass;
+		sum_xdp_pass += values[i].xdp_pass;
+		rec->cpu[i].xdp_drop = values[i].xdp_drop;
+		sum_xdp_drop += values[i].xdp_drop;
+		rec->cpu[i].xdp_redirect = values[i].xdp_redirect;
+		sum_xdp_redirect += values[i].xdp_redirect;
 	}
 	rec->total.processed = sum_processed;
 	rec->total.dropped   = sum_dropped;
 	rec->total.issue     = sum_issue;
+	rec->total.xdp_redirect  = sum_xdp_redirect;
+	rec->total.xdp_pass  = sum_xdp_pass;
+	rec->total.xdp_drop  = sum_xdp_drop;
 	return true;
 }
 
@@ -340,11 +360,20 @@ static void stats_print(struct stats_record *stats_rec,
 			if (pps > 0)
 				printf(fmt_rx, "XDP-RX",
 					i, pps, drop, err, errstr);
+			printf("cpu%d: xdp_pass %llu "
+			       "xdp_drop %llu xdp_redirect %llu\n",
+			       i, r->xdp_pass - p->xdp_pass,
+			       r->xdp_drop - p->xdp_drop,
+			       r->xdp_redirect - p->xdp_redirect);
 		}
 		pps  = calc_pps(&rec->total, &prev->total, t);
 		drop = calc_drop_pps(&rec->total, &prev->total, t);
 		err  = calc_errs_pps(&rec->total, &prev->total, t);
 		printf(fm2_rx, "XDP-RX", "total", pps, drop);
+		printf("xdp_pass %llu xdp_drop %llu xdp_redirect %llu\n",
+		       rec->total.xdp_pass - prev->total.xdp_pass,
+		       rec->total.xdp_drop - prev->total.xdp_drop,
+		       rec->total.xdp_redirect - prev->total.xdp_redirect);
 	}
 
 	/* cpumap enqueue stats */
@@ -495,8 +524,13 @@ static inline void swap(struct stats_record **a, struct stats_record **b)
 }
 
 static int create_cpu_entry(__u32 cpu, __u32 queue_size,
-			    __u32 avail_idx, bool new)
+			    __u32 avail_idx, int prog_id,
+			    bool new)
 {
+	struct cpu_map_entry prog_map_entry = {
+		.qsize = queue_size,
+		.prog_id = prog_id,
+	};
 	__u32 curr_cpus_count = 0;
 	__u32 key = 0;
 	int ret;
@@ -504,7 +538,7 @@ static int create_cpu_entry(__u32 cpu, __u32 queue_size,
 	/* Add a CPU entry to cpumap, as this allocate a cpu entry in
 	 * the kernel for the cpu.
 	 */
-	ret = bpf_map_update_elem(cpu_map_fd, &cpu, &queue_size, 0);
+	ret = bpf_map_update_elem(cpu_map_fd, &cpu, &prog_map_entry, 0);
 	if (ret) {
 		fprintf(stderr, "Create CPU entry failed (err:%d)\n", ret);
 		exit(EXIT_FAIL_BPF);
@@ -561,19 +595,19 @@ static void mark_cpus_unavailable(void)
 }
 
 /* Stress cpumap management code by concurrently changing underlying cpumap */
-static void stress_cpumap(void)
+static void stress_cpumap(__u32 prog_id)
 {
 	/* Changing qsize will cause kernel to free and alloc a new
 	 * bpf_cpu_map_entry, with an associated/complicated tear-down
 	 * procedure.
 	 */
-	create_cpu_entry(1,  1024, 0, false);
-	create_cpu_entry(1,     8, 0, false);
-	create_cpu_entry(1, 16000, 0, false);
+	create_cpu_entry(1,  1024, 0, prog_id, false);
+	create_cpu_entry(1,     8, 0, prog_id, false);
+	create_cpu_entry(1, 16000, 0, prog_id, false);
 }
 
 static void stats_poll(int interval, bool use_separators, char *prog_name,
-		       bool stress_mode)
+		       bool stress_mode, __u32 prog_id)
 {
 	struct stats_record *record, *prev;
 
@@ -591,7 +625,7 @@ static void stats_poll(int interval, bool use_separators, char *prog_name,
 		stats_print(record, prev, prog_name);
 		sleep(interval);
 		if (stress_mode)
-			stress_cpumap();
+			stress_cpumap(prog_id);
 	}
 
 	free_stats_record(record);
@@ -666,16 +700,17 @@ static int init_map_fds(struct bpf_object *obj)
 
 int main(int argc, char **argv)
 {
+	__u32 info_len = sizeof(struct bpf_prog_info), cpu_map_prog_id;
 	struct rlimit r = {10 * 1024 * 1024, RLIM_INFINITY};
 	char *prog_name = "xdp_cpu_map5_lb_hash_ip_pairs";
 	struct bpf_prog_load_attr prog_load_attr = {
 		.prog_type	= BPF_PROG_TYPE_UNSPEC,
 	};
+	struct bpf_program *prog, *cpu_map_prog;
 	struct bpf_prog_info info = {};
-	__u32 info_len = sizeof(info);
+	int prog_fd, cpu_map_prog_fd;
 	bool use_separators = true;
 	bool stress_mode = false;
-	struct bpf_program *prog;
 	struct bpf_object *obj;
 	char filename[256];
 	int added_cpus = 0;
@@ -683,7 +718,6 @@ int main(int argc, char **argv)
 	int interval = 2;
 	int add_cpu = -1;
 	int opt, err;
-	int prog_fd;
 	__u32 qsize;
 
 	n_cpus = get_nprocs_conf();
@@ -719,6 +753,24 @@ int main(int argc, char **argv)
 	}
 	mark_cpus_unavailable();
 
+	cpu_map_prog = bpf_object__find_program_by_title(obj,
+							 "xdp_cpu_prog_pass");
+	if (!cpu_map_prog) {
+		fprintf(stderr, "bpf_object__find_program_by_title failed\n");
+		return EXIT_FAIL;
+	}
+	cpu_map_prog_fd = bpf_program__fd(cpu_map_prog);
+	if (cpu_map_prog_fd < 0) {
+		fprintf(stderr, "bpf_program__fd failed\n");
+		return EXIT_FAIL;
+	}
+	err = bpf_obj_get_info_by_fd(cpu_map_prog_fd, &info, &info_len);
+	if (err) {
+		printf("can't get prog info - %s\n", strerror(errno));
+		return err;
+	}
+	cpu_map_prog_id = info.id;
+
 	/* Parse commands line args */
 	while ((opt = getopt_long(argc, argv, "hSd:s:p:q:c:xzF",
 				  long_options, &longindex)) != -1) {
@@ -763,7 +815,8 @@ int main(int argc, char **argv)
 					errno, strerror(errno));
 				goto error;
 			}
-			create_cpu_entry(add_cpu, qsize, added_cpus, true);
+			create_cpu_entry(add_cpu, qsize, added_cpus,
+					 cpu_map_prog_id, true);
 			added_cpus++;
 			break;
 		case 'q':
@@ -818,6 +871,9 @@ int main(int argc, char **argv)
 		return EXIT_FAIL_XDP;
 	}
 
+	memset(&info, 0, sizeof(info));
+	info_len = sizeof(struct bpf_prog_info);
+
 	err = bpf_obj_get_info_by_fd(prog_fd, &info, &info_len);
 	if (err) {
 		printf("can't get prog info - %s\n", strerror(errno));
@@ -825,6 +881,7 @@ int main(int argc, char **argv)
 	}
 	prog_id = info.id;
 
-	stats_poll(interval, use_separators, prog_name, stress_mode);
+	stats_poll(interval, use_separators, prog_name, stress_mode,
+		   cpu_map_prog_id);
 	return EXIT_OK;
 }
