【Linux5.4】【TUN】代码学习记录(9)--tun_chr_read_iter

【Linux5.4】【TUN】代码学习记录(9)–tun_chr_read_iter

用户调用read函数读取tun设备数据时,tun_chr_read_iter被调用。

tun_chr_read_iter

对tun_do_read进行封装

static ssize_t tun_chr_read_iter(struct kiocb *iocb, struct iov_iter *to)
{
	struct file *file = iocb->ki_filp;
	struct tun_file *tfile = file->private_data;
	struct tun_struct *tun = tun_get(tfile);
	ssize_t len = iov_iter_count(to), ret;

	if (!tun)
		return -EBADFD;
	ret = tun_do_read(tun, tfile, to, file->f_flags & O_NONBLOCK, NULL);
	ret = min_t(ssize_t, ret, len);
	if (ret > 0)
		iocb->ki_pos = ret;
	tun_put(tun);
	return ret;
}

tun_do_read

tun_do_read内主要做两件事:①接收网络传来的skb数据,②将①中的数据交给用户。
如果tun_do_read是由tun_chr_read_iter调用的,那么参数ptr是NULL,所以需要tun_ring_recv获取ptr指针,再由struct sk_buff *skb = ptr得到skb,①完成。
调用tun_put_user将数据传入用户空间,②完成。
这里需要注意的是,在tfile中有一个tx_ring,是一个生产消费模型使用的“环形内存”,由生产者放入数据,消费者(也就是tun_ring_recv函数)读取数据,那么这个生产者按逻辑讲应该是内核的网络协议栈,网络协议栈收到物理网卡传来的数据,处理后如果要交付给tun设备,就会将数据放入相应的tfile中的tx_ring里。

static ssize_t tun_do_read(struct tun_struct *tun, struct tun_file *tfile,
			   struct iov_iter *to,
			   int noblock, void *ptr)
{
	ssize_t ret;
	int err;

	tun_debug(KERN_INFO, tun, "tun_do_read\n");

	if (!iov_iter_count(to)) {
		tun_ptr_free(ptr);
		return 0;
	}

	if (!ptr) {
		/* Read frames from ring */
		ptr = tun_ring_recv(tfile, noblock, &err);
		if (!ptr)
			return err;
	}

	if (tun_is_xdp_frame(ptr)) {
		struct xdp_frame *xdpf = tun_ptr_to_xdp(ptr);

		ret = tun_put_user_xdp(tun, tfile, xdpf, to);
		xdp_return_frame(xdpf);
	} else {
		struct sk_buff *skb = ptr;

		ret = tun_put_user(tun, tfile, skb, to);
		if (unlikely(ret < 0))
			kfree_skb(skb);
		else
			consume_skb(skb);
	}
	return ret;
}

tun_put_user

tun_put_user较长,可以只看关键部分:
上传数据到用户空间实际是由skb_copy_datagram_iter完成的。

/* Put packet to the user space buffer */
static ssize_t tun_put_user(struct tun_struct *tun,
			    struct tun_file *tfile,
			    struct sk_buff *skb,
			    struct iov_iter *iter)
{
	...
	skb_copy_datagram_iter(skb, vlan_offset, iter, skb->len - vlan_offset);
	...
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
这个错误通常表示在编译`aqua-sim-routing-dummy.cc`文件时出现了问题。根据日志,这是通过使用g++编译器尝试编译该文件的命令: ```shell /usr/bin/g++ -O0 -ggdb -g3 -Wall -Werror -std=c++11 -Wno-error=deprecated-declarations -fstrict-aliasing -Wstrict-aliasing -fPIC -pthread -I. -I.. -DNS3_BUILD_PROFILE_DEBUG -DNS3_ASSERT_ENABLE -DNS3_LOG_ENABLE -DHAVE_SYS_IOCTL_H=1 -DHAVE_IF_NETS_H=1 -DHAVE_NET_ETHERNET_H=1 -DHAVE_PACKET_H=1 -DHAVE_IF_TUN_H=1 -DHAVE_GSL=1 -DHAVE_SQLITE3=1 ../src/aqua-sim-ng/model/aqua-sim-routing-dummy.cc -c -o /home/fjl/ns-allinone-3.26/ns-3.26/build/src/aqua-sim-ng/model/aqua-sim-routing-dummy.cc.1.o ``` 根据命令和错误信息,可能有以下一些原因导致构建失败: 1. 缺少某些依赖项:请确保你的系统中安装了所有必需的依赖项。在这个特定的情况下,确保你的系统中安装了g++编译器、pthread库、以及其他相关的头文件和库。 2. 编译器错误:有时候编译器可能会有一些问题,尝试更新或更换你的编译器版本,可能会解决该问题。 3. 文件路径错误:检查`../src/aqua-sim-ng/model/aqua-sim-routing-dummy.cc`文件是否存在,并确保路径正确。 4. 代码错误:在`aqua-sim-routing-dummy.cc`文件中可能存在语法错误或其他编译错误。请仔细检查该文件,并确保代码没有问题。 希望这些提示能够帮助你解决构建失败的问题!如果还有其他疑问,请随时提问。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值