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