02 编程示例
2.1 启动设备
使用 tap/tun 设备,需要先进行一些初始化工作,如下代码所示:
int tun_alloc(char *dev, int flags)
{
assert(dev != NULL);
struct ifreq ifr;
int fd, err;
char *clonedev = "/dev/net/tun";
if ((fd = open(clonedev, O_RDWR)) < 0) {
return fd;
}
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = flags;
if (*dev != '\0') {
strncpy(ifr.ifr_name, dev, IFNAMSIZ);
}
if ((err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0) {
close(fd);
return err;
}
// 一旦设备开启成功,系统会给设备分配一个名称,对于tun设备,一般为tunX,X为从0开始的编号;
// 对于tap设备,一般为tapX
strcpy(dev, ifr.ifr_name);
return fd;
}首先打开字符设备文件 /dev/net/tun,然后用 ioctl 注册设备的工作模式,是 tap 还是 tun。这个模式由结构体 struct ifreq 的属性 ifr_flags 来定义,它有以下表示:
•IFF_TUN: 表示创建一个 tun 设备。
•IFF_TAP: 表示创建一个 tap 设备。
•IFF_NO_PI: 表示不包含包头信息,默认的,每个数据包传到用户空间时,都会包含一个附加的包头来保存包信息,这个表示不加包头。
•IFF_ONE_QUEUE:表示采用单一队列模式。
还是有一个属性是 ifr_name,表示设备的名字,它可以由用户自己指定,也可以由系统自动分配,比如 tapX、tunX,X 从 0 开始编号。
ioctl 完了之后,文件描述符 fd 就和设备建立起了关联,之后就可以根据 fd 进行 read 和 write 操作了。