包含标签 kernel 的文章

EXPORT SYMBOL

1. 背景 EXPORT_SYMBOL只出现在2.6内核中,在2.4内核默认的非static 函数和变量都会自动导入到kernel 空间的, 都不用EXPORT_SYMBOL() 做标记的。2.6就必须用EXPORT_SYMBOL() 来导出来(因为2.6默认不导出所有的符号) 2. EXPORT_SYMBOL的作用 EXPORT_SYMBOL标签内定义的函数或者符号对全部内核代码公开, 不用修改内核代码就可以在您的内核模块中直接调用,即使用EXPORT_SYMBOL可以将一个函数以符号的方式导出给其他模块使用 EXPORT_SYMBOL(符号名); 可以导出static函数到符号表中 EXPORT_SYMBOL_GPL(符号名) //用于GPL协议认证的模块 EXPORT_SYMBOL_GPL的符号必须要用MODULE_LICENSE("GPL")或者用MODULE_LICENSE("Dual BSD/GPL")之后才能在模块中引用。 而且MODULE_LICENSE("char")中的char不可以是任意字符,否则错误和没有MODULE_LICENSE效果一样。 这里要和System.map做一下对比: System.map 中的是连接时的函数地址。连接完成以后,在2.6内核运行过程中,是不知道哪个符号在哪个地址的。 EXPORT_SYMBOL 的符号,是把这些符号和对应的地址保存起来,在内核运行的过程中,可以找到这些符号对应的地址。 而模块在加载过程中,其本质就是能动态连接到内核,如果在模块中引用了内核或其它模块的符号, 就要EXPORT_SYMBOL这些符号,这样才能找到对应的地址连接 3. 使用方法 在模块函数定义之后使用EXPORT_SYMBOL(函数名) 在掉用该函数的模块中使用extern对之声明 首先加载定义该函数的模块,再加载调用该函数的模块 另外,在编译调用某导出函数的模块时,往往会有WARNING: “****” [**********] undefined! 使用dmesg命令后会看到相同的信息。开始我以为只要有这个错误就不能加载模块,后来上网查了一下, 发现这主要是因为在编译连接的时候还没有和内核打交道,当然找不到symbol了,但是由于你生成的是一个内核模块, 所以LD不提示error,而是给出一个warning,寄希望于在insmod的时候,内核能够把这个symbol连接上 1.EXPORT_SYMBOL EXPORT_SYMBOL( my_pub_func); 在预编译阶段会解析为: extern void *__crc_my_pub_func __attribute__((weak)); static const unsigned long __kcrctab_my_pub_func __attribute__((__used__)) __attribute__((section("__kcrctab" ""), unused)) = (unsigned long) &__crc_my_pub_func; static const char __kstrtab_my_pub_func[] __attribute__((section("__ksymtab_strings"))) = "" "my_pub_func"; static const struct kernel_symbol __ksymtab_my_pub_func __attribute__((__used__)) __attribute__((section("__ksymtab" ""), unused)) = { (unsigned long)&my_pub_func, __kstrtab_my_pub_func }; 很显然__ksymtab_my_pub_func存储了my_pub_func的地址和符号信息,该符号对应的地址 只有insmod后才会确定; __ksymtab_my_pub_func会链接到__ksymtab section,__ksymtab section中的所有内容就构成了 内核"导出"的符号表,这个表在insmod 时候会用到.……

阅读全文

vpp和linux内核协议栈通信

1. 背景介绍 基于VPP开发一款网络设备,除使用VPP框架实现端口数据报文转发外,还需要对设备进行配置和管理, 比较常用的是要实现ssh、web等相关服务,另外,由于VPP并未实现dhcp server的功能,控制面可能还需移植isc-dhcp类似的dhcp server。 相关的用户态程序是基于Linux内核的socket来收发包的,因此,需要实现VPP和Linux内核协议栈通信的方法, 可以将访问控制面的报文由VPP上送至Linux协议的协议栈。 2. 实现原理 VPP和Linux内核协议栈通信有两种方法,分别是基于Linux的TAP/TUN和VETH两种机制, 对这两种机制不了解的朋友,建议先阅读下如下两个衔接的内容: TUN/TAP:https://segmentfault.com/a/1190000009249039 VETH:https://segmentfault.com/a/1190000009251098 基于TAP/TUN的方法: 如上图,PC的地址是192.168.1.2,Linux Kernel的管理接口地址是192.168.1.1,需要PC通过VPP可以ping同Linux内核的192.168.1.1地址 技术原理图如上,物理网卡对应VPP中的GE4/0/0,VPP创建tap接口,使用l2 bridge机制将GE4/0/0和tap桥接,进入GE4/0/0的报文通过l2 bridge转发到TAP, VPP的TAP相当于用户态进程,另一端对应的是Linux内核中的TAP接口,报文通过TAP机制重入到Linux内核,实现了VPP到控制面的通信 实现命令: vpp#set int l2 bridge GigabitEthernet4/0/0 1 vpp#set int state GigabitEthernet4/0/0 up vpp#tap connect lstack vpp#set int l2 bridge tap-0 1 vpp#set int state tap-0 up 上述操作完成后,在linux后台,ifconfig发现多了一个lstack接口,给lstack接口配置好IP地址,就可以实现PC和设备的通信了。 基于VETH方法: VETH技术原理如上图,通过在vpp上创建host-interface的方式实现,使用VETH方式的效率更高,实际使用时推荐此种方法 配置步骤如下 linux后台配置: ~# ip netns add ns0 ~# ip link add vpp0 type veth peer name vethns0 ~# ip link set vethns0 netns ns0 ~# ip netns exec ns0 ip link set lo up ~# ip netns exec ns0 ip link set vethns0 up ~# ip netns exec ns0 ip addr add 192.……

阅读全文

kernel 字符设备驱动

1. 字符设备 Linux字符设备是一种按字节来访问的设备,字符驱动则负责驱动字符设备,这样的驱动通常实现open、close、read和write系统调用。例如:串口、Led、按键等 通过字符设备文件(/dev/xxx),应用程序可以使用相应的字符设备驱动来控制字符设备 2. 如何创建字符设备 使用命令mknod : mknod /dev/文件名 c 主设备号 次设备号 (查看主设备号:cat /proc/devices) 使用函数创建:mknod() int mknod(const char *pathname, mode_t mode, dev_t dev); 3. 文件系统与字符设备驱动程序之间的关系 在Linux系统中,每一个打开的文件,在内核中都会关联一个struct file结构,它是由内核在打开文件时创建,在文件关闭后释放。 struct file结构中的重要成员 * struct file_operations* f_op; //文件操作函数集 * loff_t f_pos; //文件读写指针 每一个存在于文件系统中的文件都会关联一个inode结构,该结构主要用来记录文件物理上的信息。因此,它和代表打开文件的file结构是不同的,一个文件没有被打开时不会关联file结构,但是会关联一个inode结构(存于磁盘,操作文件时在内存中建立相应的映射结构) 注:inode用于存储文件的元信息(除了文件名的所有信息),中文译名索引节点 从上图可知,系统实质上是把字符设备的注册表看成了文件。其中chrdevs[]在内核的定义如下 static struct char_device_struct { struct char_device_struct *next; unsigned int major; unsigned int baseminor; int minorct; char name[64]; struct cdev *cdev; /* will die */ } *chrdevs[CHRDEV_MAJOR_HASH_SIZE]; 4.……

阅读全文

kernel module编程

1. Linux Kernel Module是什么 Linux Kernel Module是一段可以在运行时被加载到Linux Kernel中的代码,可以使用Kernel Functions。Linux Kernel Module的用途很广,最常见的例子就是Device Driver,也就是设备驱动程序。 如果没有Linux Kernel Module,每一行修改Kernel代码,每一个新增的Kernel功能特性,都需要重新编译Kernel,大大浪费了时间和效率。 2. kernel module编程 [root@localhost test]# ll 总用量 16 -rw-r--r--. 1 root root 728 4月 17 10:28 hello.c -rw-r--r--. 1 root root 229 4月 17 10:24 Makefile -rw-r--r--. 1 root root 190 4月 17 10:26 mymax.c -rw-r--r--. 1 root root 70 4月 17 10:17 mymax.h [root@localhost test]# cat hello.c #include <linux/init.h> /* Needed for the module-macros */ #include <linux/module.……

阅读全文

linux内核定制

1. 下载内核源代码 从 http://www.kernel.org 下载内核源代码RPM包 例如linux-2.6.27.62.tar.bz2 2. 解压内核 # bzip2 -d linux-2.6.27.62.tar.bz2 # tar -xvf linux-2.6.27.62.tar 3. 定制内核 #定制内核有很多种方法:make config(最基本方法),make defconfig(默认的方法) # make config # make defconfig # make menuconfig #会生成.config文件,这个文件也可以从/boot路径下拷贝 #Y是该选项能够构建到内核内部 #M是构建模块 4. 构建内核 # make clean //这一步最好执行一下 # make -j2 5. 打包成rpm # make rpm 6. 安装并引导内核 # make modules_install //安装模块 # make install //安装内核 #这时,系统会自动在你的启动菜单中加入启动新内核的菜单,如 [root@localhost linux-2.6.27.62]# cat /boot/grub/menu.lst default=1 timeout=5 splashimage=(hd0,0)/grub/splash.xpm.gz hiddenmenu title Red Hat Enterprise Linux AS (2.……

阅读全文

WCG内核修改

1. 下载源代码包 从 http://vault.centos.org 下载内核源代码RPM包 2. 安装源代码包 [root@wcg-9-73 df]# rpm -ivh kernel-3.10.0-1062.el7.src.rpm 执行命令后会生成/root/rpmbuild路径,包含SPECS和SOURCES 3. 修改源码 [root@wcg-9-73 df]# cd /root/rpmbuild/SOURCES [root@wcg-9-73 SOURCES]# xz -d linux-3.10.0-1062.el7.tar.xz [root@wcg-9-73 SOURCES]# tar -xvf linux-3.10.0-1062.el7.tar #将修改后的代码替换 [root@wcg-9-73 SOURCES]# cd linux-3.10.0-1062.el7/ [root@wcg-9-73 linux-3.10.0-1062.el]# cd net/ipv4/ [root@wcg-9-73 ipv4]# rm -rf udp.c && cp -rf /root/df/udp.c . [root@wcg-9-73 ipv4]# cd ../../include/uapi/linux/ [root@wcg-9-73 linux]# rm -rf udp.h && cp -rf /root/df/udp.h . [root@wcg-9-73 linux]# cd ../../../ [root@wcg-9-73 SOURCES]# tar -cvf linux-3.……

阅读全文

最近文章

分类

标签

友情链接

其它