xdp_rxq_info_kern.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. /* SPDX-License-Identifier: GPL-2.0
  2. * Copyright (c) 2017 Jesper Dangaard Brouer, Red Hat Inc.
  3. *
  4. * Example howto extract XDP RX-queue info
  5. */
  6. #include <uapi/linux/bpf.h>
  7. #include <uapi/linux/if_ether.h>
  8. #include <uapi/linux/in.h>
  9. #include <bpf/bpf_helpers.h>
  10. /* Config setup from with userspace
  11. *
  12. * User-side setup ifindex in config_map, to verify that
  13. * ctx->ingress_ifindex is correct (against configured ifindex)
  14. */
  15. struct config {
  16. __u32 action;
  17. int ifindex;
  18. __u32 options;
  19. };
  20. enum cfg_options_flags {
  21. NO_TOUCH = 0x0U,
  22. READ_MEM = 0x1U,
  23. SWAP_MAC = 0x2U,
  24. };
  25. struct {
  26. __uint(type, BPF_MAP_TYPE_ARRAY);
  27. __type(key, int);
  28. __type(value, struct config);
  29. __uint(max_entries, 1);
  30. } config_map SEC(".maps");
  31. /* Common stats data record (shared with userspace) */
  32. struct datarec {
  33. __u64 processed;
  34. __u64 issue;
  35. };
  36. struct {
  37. __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
  38. __type(key, u32);
  39. __type(value, struct datarec);
  40. __uint(max_entries, 1);
  41. } stats_global_map SEC(".maps");
  42. #define MAX_RXQs 64
  43. /* Stats per rx_queue_index (per CPU) */
  44. struct {
  45. __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
  46. __type(key, u32);
  47. __type(value, struct datarec);
  48. __uint(max_entries, MAX_RXQs + 1);
  49. } rx_queue_index_map SEC(".maps");
  50. static __always_inline
  51. void swap_src_dst_mac(void *data)
  52. {
  53. unsigned short *p = data;
  54. unsigned short dst[3];
  55. dst[0] = p[0];
  56. dst[1] = p[1];
  57. dst[2] = p[2];
  58. p[0] = p[3];
  59. p[1] = p[4];
  60. p[2] = p[5];
  61. p[3] = dst[0];
  62. p[4] = dst[1];
  63. p[5] = dst[2];
  64. }
  65. SEC("xdp_prog0")
  66. int xdp_prognum0(struct xdp_md *ctx)
  67. {
  68. void *data_end = (void *)(long)ctx->data_end;
  69. void *data = (void *)(long)ctx->data;
  70. struct datarec *rec, *rxq_rec;
  71. int ingress_ifindex;
  72. struct config *config;
  73. u32 key = 0;
  74. /* Global stats record */
  75. rec = bpf_map_lookup_elem(&stats_global_map, &key);
  76. if (!rec)
  77. return XDP_ABORTED;
  78. rec->processed++;
  79. /* Accessing ctx->ingress_ifindex, cause BPF to rewrite BPF
  80. * instructions inside kernel to access xdp_rxq->dev->ifindex
  81. */
  82. ingress_ifindex = ctx->ingress_ifindex;
  83. config = bpf_map_lookup_elem(&config_map, &key);
  84. if (!config)
  85. return XDP_ABORTED;
  86. /* Simple test: check ctx provided ifindex is as expected */
  87. if (ingress_ifindex != config->ifindex) {
  88. /* count this error case */
  89. rec->issue++;
  90. return XDP_ABORTED;
  91. }
  92. /* Update stats per rx_queue_index. Handle if rx_queue_index
  93. * is larger than stats map can contain info for.
  94. */
  95. key = ctx->rx_queue_index;
  96. if (key >= MAX_RXQs)
  97. key = MAX_RXQs;
  98. rxq_rec = bpf_map_lookup_elem(&rx_queue_index_map, &key);
  99. if (!rxq_rec)
  100. return XDP_ABORTED;
  101. rxq_rec->processed++;
  102. if (key == MAX_RXQs)
  103. rxq_rec->issue++;
  104. /* Default: Don't touch packet data, only count packets */
  105. if (unlikely(config->options & (READ_MEM|SWAP_MAC))) {
  106. struct ethhdr *eth = data;
  107. if (eth + 1 > data_end)
  108. return XDP_ABORTED;
  109. /* Avoid compiler removing this: Drop non 802.3 Ethertypes */
  110. if (ntohs(eth->h_proto) < ETH_P_802_3_MIN)
  111. return XDP_ABORTED;
  112. /* XDP_TX requires changing MAC-addrs, else HW may drop.
  113. * Can also be enabled with --swapmac (for test purposes)
  114. */
  115. if (unlikely(config->options & SWAP_MAC))
  116. swap_src_dst_mac(data);
  117. }
  118. return config->action;
  119. }
  120. char _license[] SEC("license") = "GPL";