*  Example howto extract XDP RX-queue info
  */
 #include <uapi/linux/bpf.h>
+#include <uapi/linux/if_ether.h>
+#include <uapi/linux/in.h>
 #include "bpf_helpers.h"
 
 /* Config setup from with userspace
 struct config {
        __u32 action;
        int ifindex;
+       __u32 options;
+};
+enum cfg_options_flags {
+       NO_TOUCH = 0x0U,
+       READ_MEM = 0x1U,
 };
 struct bpf_map_def SEC("maps") config_map = {
        .type           = BPF_MAP_TYPE_ARRAY,
        if (key == MAX_RXQs)
                rxq_rec->issue++;
 
+       /* Default: Don't touch packet data, only count packets */
+       if (unlikely(config->options & READ_MEM)) {
+               struct ethhdr *eth = data;
+
+               if (eth + 1 > data_end)
+                       return XDP_ABORTED;
+
+               /* Avoid compiler removing this: Drop non 802.3 Ethertypes */
+               if (ntohs(eth->h_proto) < ETH_P_802_3_MIN)
+                       return XDP_ABORTED;
+       }
+
        return config->action;
 }
 
 
        {"sec",         required_argument,      NULL, 's' },
        {"no-separators", no_argument,          NULL, 'z' },
        {"action",      required_argument,      NULL, 'a' },
+       {"readmem",     no_argument,            NULL, 'r' },
        {0, 0, NULL,  0 }
 };
 
 struct config {
        __u32 action;
        int ifindex;
+       __u32 options;
+};
+enum cfg_options_flags {
+       NO_TOUCH = 0x0U,
+       READ_MEM = 0x1U,
 };
 #define XDP_ACTION_MAX (XDP_TX + 1)
 #define XDP_ACTION_MAX_STRLEN 11
        printf("\n");
 }
 
+static char* options2str(enum cfg_options_flags flag)
+{
+       if (flag == NO_TOUCH)
+               return "no_touch";
+       if (flag & READ_MEM)
+               return "read";
+       fprintf(stderr, "ERR: Unknown config option flags");
+       exit(EXIT_FAIL);
+}
+
 static void usage(char *argv[])
 {
        int i;
 
 static void stats_print(struct stats_record *stats_rec,
                        struct stats_record *stats_prev,
-                       int action)
+                       int action, __u32 cfg_opt)
 {
        unsigned int nr_rxqs = bpf_map__def(rx_queue_index_map)->max_entries;
        unsigned int nr_cpus = bpf_num_possible_cpus();
        int i;
 
        /* Header */
-       printf("\nRunning XDP on dev:%s (ifindex:%d) action:%s\n",
-              ifname, ifindex, action2str(action));
+       printf("\nRunning XDP on dev:%s (ifindex:%d) action:%s options:%s\n",
+              ifname, ifindex, action2str(action), options2str(cfg_opt));
 
        /* stats_global_map */
        {
        *b = tmp;
 }
 
-static void stats_poll(int interval, int action)
+static void stats_poll(int interval, int action, __u32 cfg_opt)
 {
        struct stats_record *record, *prev;
 
        while (1) {
                swap(&prev, &record);
                stats_collect(record);
-               stats_print(record, prev, action);
+               stats_print(record, prev, action, cfg_opt);
                sleep(interval);
        }
 
 
 int main(int argc, char **argv)
 {
+       __u32 cfg_options= NO_TOUCH ; /* Default: Don't touch packet memory */
        struct rlimit r = {10 * 1024 * 1024, RLIM_INFINITY};
        struct bpf_prog_load_attr prog_load_attr = {
                .prog_type      = BPF_PROG_TYPE_XDP,
        int interval = 2;
        __u32 key = 0;
 
+
        char action_str_buf[XDP_ACTION_MAX_STRLEN + 1 /* for \0 */] = { 0 };
        int action = XDP_PASS; /* Default action */
        char *action_str = NULL;
                        action_str = (char *)&action_str_buf;
                        strncpy(action_str, optarg, XDP_ACTION_MAX_STRLEN);
                        break;
+               case 'r':
+                       cfg_options |= READ_MEM;
+                       break;
                case 'h':
                error:
                default:
                }
        }
        cfg.action = action;
+       cfg.options = cfg_options;
 
        /* Trick to pretty printf with thousands separators use %' */
        if (use_separators)
                return EXIT_FAIL_XDP;
        }
 
-       stats_poll(interval, action);
+       stats_poll(interval, action, cfg_options);
        return EXIT_OK;
 }