blob: e64ed7fdbefeac93cd5443c540b18d41b0e6ef6f [file] [log] [blame]
Haoba736572020-09-12 02:05:29 +08001
2#include <linux/netdevice.h>
3#include <linux/ethtool.h>
4#if IFNAMSIZ != 16
5#error "IFNAMSIZ != 16 is not supported"
6#endif
7#define MAX_QUEUE_NUM 1024
8
9/**
10* This union is use to store name of the specified interface
11* and read it as two different data types
12*/
13union name_buf{
14 char name[IFNAMSIZ];
15 struct {
16 u64 hi;
17 u64 lo;
18 }name_int;
19};
20
21/* data retrieved in tracepoints */
22struct queue_data{
23 u64 total_pkt_len;
24 u32 num_pkt;
25 u32 size_64B;
26 u32 size_512B;
27 u32 size_2K;
28 u32 size_16K;
29 u32 size_64K;
30};
31
32/* array of length 1 for device name */
33BPF_ARRAY(name_map, union name_buf, 1);
34/* table for transmit & receive packets */
35BPF_HASH(tx_q, u16, struct queue_data, MAX_QUEUE_NUM);
36BPF_HASH(rx_q, u16, struct queue_data, MAX_QUEUE_NUM);
37
38static inline int name_filter(struct sk_buff* skb){
39 /* get device name from skb */
40 union name_buf real_devname;
41 struct net_device *dev;
42 bpf_probe_read(&dev, sizeof(skb->dev), ((char *)skb + offsetof(struct sk_buff, dev)));
43 bpf_probe_read(&real_devname, IFNAMSIZ, dev->name);
44
45 int key=0;
46 union name_buf *leaf = name_map.lookup(&key);
47 if(!leaf){
48 return 0;
49 }
50 if((leaf->name_int).hi != real_devname.name_int.hi || (leaf->name_int).lo != real_devname.name_int.lo){
51 return 0;
52 }
53
54 return 1;
55}
56
57static void updata_data(struct queue_data *data, u64 len){
58 data->total_pkt_len += len;
59 data->num_pkt ++;
60 if(len / 64 == 0){
61 data->size_64B ++;
62 }
63 else if(len / 512 == 0){
64 data->size_512B ++;
65 }
66 else if(len / 2048 == 0){
67 data->size_2K ++;
68 }
69 else if(len / 16384 == 0){
70 data->size_16K ++;
71 }
72 else if(len / 65536 == 0){
73 data->size_64K ++;
74 }
75}
76
77TRACEPOINT_PROBE(net, net_dev_start_xmit){
78 /* read device name */
79 struct sk_buff* skb = (struct sk_buff*)args->skbaddr;
80 if(!name_filter(skb)){
81 return 0;
82 }
83
84 /* update table */
85 u16 qid = skb->queue_mapping;
86 struct queue_data newdata;
87 __builtin_memset(&newdata, 0, sizeof(newdata));
88 struct queue_data *data = tx_q.lookup_or_try_init(&qid, &newdata);
89 if(!data){
90 return 0;
91 }
92 updata_data(data, skb->len);
93
94 return 0;
95}
96
97TRACEPOINT_PROBE(net, netif_receive_skb){
zhenwei pia55192b2020-12-21 19:49:36 +080098 struct sk_buff skb;
99
100 bpf_probe_read(&skb, sizeof(skb), args->skbaddr);
101 if(!name_filter(&skb)){
Haoba736572020-09-12 02:05:29 +0800102 return 0;
103 }
104
zhenwei pia55192b2020-12-21 19:49:36 +0800105 /* case 1: if the NIC does not support multi-queue feature, there is only
106 * one queue(qid is always 0).
107 * case 2: if the NIC supports multi-queue feature, there are several queues
108 * with different qid(from 0 to n-1).
109 * The net device driver should mark queue id by API 'skb_record_rx_queue'
110 * for a recieved skb, otherwise it should be a BUG(all of the packets are
111 * reported as queue 0). For example, virtio net driver is fixed for linux:
112 * commit: 133bbb18ab1a2("virtio-net: per-queue RPS config")
113 */
114 u16 qid = 0;
115 if (skb_rx_queue_recorded(&skb))
116 qid = skb_get_rx_queue(&skb);
117
Haoba736572020-09-12 02:05:29 +0800118 struct queue_data newdata;
119 __builtin_memset(&newdata, 0, sizeof(newdata));
120 struct queue_data *data = rx_q.lookup_or_try_init(&qid, &newdata);
121 if(!data){
122 return 0;
123 }
zhenwei pia55192b2020-12-21 19:49:36 +0800124 updata_data(data, skb.len);
Haoba736572020-09-12 02:05:29 +0800125
126 return 0;
127}