rprobe、kretprobe使用例子

kretbrobe:

    Linux协议栈处理发送流程时,在发送驱动函数前会通过__netdev_pick_tx选择一个发送队列,当选择好一个发送队列后,协议栈会将其设置到sk->sk_tx_queue_mapping,这样后续的发送流程就不需要再去选择。

static u16 __netdev_pick_tx(struct net_device *dev, struct sk_buff *skb)
{
	struct sock *sk = skb->sk;
	int queue_index = sk_tx_queue_get(sk);

	//skb->ooo_okay对于udp没有意义,针对tcp,当tcp层的发送端检测到所有
	//发送出去的skb都已经被ack时,就会对ooo_okay置1,这时候这里就允许重新
	//选择一个不一样的队列了,否则会沿用上一次选择的队列
	if (queue_index < 0 || skb->ooo_okay ||
	    queue_index >= dev->real_num_tx_queues) {
		int new_index = get_xps_queue(dev, skb);

		if (new_index < 0)
			new_index = skb_tx_hash(dev, skb);

		if (queue_index != new_index && sk &&
		    sk_fullsock(sk) &&
		    rcu_access_pointer(sk->sk_dst_cache))
			sk_tx_queue_set(sk, new_index);

		queue_index = new_index;
	}

	return queue_index;
}

    下面主要是使用retkprobe探测tcp流选择的队列信息:

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/kprobes.h>
#include <linux/ktime.h>
#include <linux/limits.h>
#include <linux/sched.h>

#include <uapi/linux/tcp.h>
#include <uapi/linux/if_ether.h>
#include <uapi/linux/if_packet.h>
#include <linux/ip.h>
#include <linux/socket.h>
#include <linux/net.h>
#include <net/sock.h>

//需要探测的函数名称
static char func_name[NAME_MAX] = "__netdev_pick_tx";

struct my_data {
	ktime_t entry_stamp;
};

static int count=0;
static long int queue_counts[32] = {};

static __be32 cpu_src[32] = {};
static __be32 cpu_dst[32] = {};


static int entry_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
{
	//regs->si为__netdev_pick_tx的第二个参数(skb)
	struct sk_buff *skb = regs->si;
	const struct iphdr *iph;
 	iph = ip_hdr(skb);
	//按cpu_id为索引,将ip的源、宿信息保存到对应的数组里
	int cpu_id = raw_smp_processor_id();
	cpu_src[cpu_id] = iph->saddr;
	cpu_dst[cpu_id] = iph->daddr;
	int ooo_okay = skb->ooo_okay;
	struct sock *sk = skb->sk;
	int queue_index = sk_tx_queue_get(sk);
	if (cpu_src[cpu_id] == 2196511856 && cpu_dst[cpu_id] == 2347506800) {
		net_info_ratelimited("entry handle ooo_okay: %d, queue_index:%d, sk: %p \n", ooo_okay,queue_index, sk);
	}
	//net_info_ratelimited("netdev_cap_txqueue %pI4 -> %pI4 %u ~ %u cpu: %d %u ~ %u \n", &iph->saddr,&iph->daddr, iph->saddr, iph->daddr, cpu_id, cpu_src[cpu_id], cpu_dst[cpu_id]);
	return 0;
}

static int ret_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
{
	//获取函数的返回值
	int queue_index = regs_return_value(regs);

	//将当前选择的队列计数加1
	int cpu_id = raw_smp_processor_id();
	if (cpu_src[cpu_id] == 2196511856 && cpu_dst[cpu_id] == 2347506800) {
		queue_counts[queue_index]++;
	}
	
	net_info_ratelimited("per cpu packets %ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld \n %ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld \n %ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,\n %ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld \n",
				queue_counts[0],queue_counts[1],queue_counts[2],queue_counts[3],queue_counts[4],queue_counts[5],queue_counts[6],queue_counts[7],
				queue_counts[8],queue_counts[9],queue_counts[10],queue_counts[11],queue_counts[12],queue_counts[13],queue_counts[14],queue_counts[15],
				queue_counts[16],queue_counts[17],queue_counts[18],queue_counts[19],queue_counts[20],queue_counts[21],queue_counts[22],queue_counts[23],
				queue_counts[24],queue_counts[25],queue_counts[26],queue_counts[27],queue_counts[28],queue_counts[29],queue_counts[30],queue_counts[31]);
}

static struct kretprobe my_kretprobe = {
	//handler退出函数时执行
	.handler		= ret_handler,
	//entry_handle进入函数时执行
	.entry_handler	= entry_handler,
	.data_size		= sizeof(struct my_data),
	/* Probe up to 20 instances concurrently. */
	.maxactive		= 20,
};


static int __init kretprobe_init(void)
{
	int ret;

	//注册retkprobe
	my_kretprobe.kp.symbol_name = func_name;
	ret = register_kretprobe(&my_kretprobe);
	if (ret < 0) {
		printk(KERN_INFO "register_kretprobe failed, returned %d\n",
				ret);
		return -1;
	}
	printk(KERN_INFO "Planted return probe at %s: %p\n",
			my_kretprobe.kp.symbol_name, my_kretprobe.kp.addr);
	return 0;
}

static void __exit kretprobe_exit(void)
{
	unregister_kretprobe(&my_kretprobe);
	printk(KERN_INFO "kretprobe at %p unregistered\n",
			my_kretprobe.kp.addr);
}

module_init(kretprobe_init)
module_exit(kretprobe_exit)
MODULE_LICENSE("GPL");

 

kprobe

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/kprobes.h>
#include <linux/ktime.h>
#include <linux/limits.h>
#include <linux/sched.h>

#include <uapi/linux/tcp.h>
#include <uapi/linux/if_ether.h>
#include <uapi/linux/if_packet.h>
#include <linux/ip.h>
#include <linux/socket.h>
#include <linux/net.h>
#include <net/sock.h>

static void handler_post(struct kprobe *p, struct pt_regs *regs,
                unsigned long flags)
{
        struct sk_buff *skb = (struct sk_buff *)(regs->di);
        struct ethhdr *eth = eth_hdr(skb);
        struct iphdr *iph = ip_hdr(skb);
        if (skb->pkt_type == PACKET_OTHERHOST) {
                printk("receive other host skb src_ip: %pI4, dst_ip: %pI4, skb->dest_mac: %pM, dev->mac: %pM \n", &iph->saddr, &iph->daddr, eth->h_dest, skb->dev->dev_addr);
        }

}

static struct kprobe my_kprobe = {
        .symbol_name    = "ip_rcv",
        .post_handler = handler_post
};

static int __init kprobe_init(void)
{
        int ret;
        ret = register_kprobe(&my_kprobe);
        if (ret < 0) {
                printk(KERN_INFO "register_kprobe failed, returned %d\n",
                                ret);
                return -1;
        }
        printk(KERN_INFO "Planted return probe at %s \n",
                        my_kprobe.symbol_name);
        return 0;
}

static void __exit kprobe_exit(void)
{
        unregister_kprobe(&my_kprobe);
        printk(KERN_INFO "kprobe at %s unregistered\n",
                        my_kprobe.symbol_name);
}

module_init(kprobe_init)
module_exit(kprobe_exit)
MODULE_LICENSE("GPL");

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值