QNX中自定义网卡驱动ioctl的方法
QNX中自定义网卡驱动ioctl的方法之前的文章“QNX上使用硬件时间戳进行PTP对时”提到过QNX中要使用硬件时间戳进行PTP对时的话需要在驱动中解析接收和发送的报文是否是PTP报文以便依据PTP报文的硬件时间戳进行高精度对时我们在实际使用中一般只会有一个网口用于PTP对时如果不加区分默认对所有的网口报文都进行PTP解析会在网络性能上带来极大的浪费所以我们希望能够根据实际情况动态的指定哪些网口的数据不需要做PTP解析以此来提高网络通信的效率。这种驱动动态配置最通用的方法就是增加自定义的ioctl命令在应用层调用ioctl系统调用通过自定义的ioctl命令下发数据给驱动由驱动根据应用层数据执行相应的动作在我们的这个需求下那就是自定义一条网卡的ioctl命令指定ptp网口同时下发网口ID后续由驱动根据网口ID来对网络报文做相应的操作解析或者不解析报文。示例ioctl(sock_fd, SIOCGDRVSPEC, ifd)其中sock_fd是socket描述符用于标识网卡设备SIOCGDRVSPEC是网卡驱动原生配置指令我们的ptp配置项包含在参数ifd里。在应用层调用上述指令同时在网卡驱动里增加日志来观测配置是否成功结果发现驱动层能正确获取ioctl命令进入ioctl的SIOCGDRVSPEC处理函数但是ptp配置项的数据ifd却无法正确传递给驱动无法进行ptp配置。查阅资料发现QNX虽然包含了对ioctl接口的支持但是由于其微内核的特性导致ioctl在QNX上的行为与Linux这种宏内核的行为有些不一致宏内核中驱动提供的ioctl只是一个方法当应用层调用ioctl时ioctl只是陷入内核态获取系统特权级别但是ioctl执行时的上下文其实还是处在应用程序中也就是ioctl执行时依然处在应用程序的进程地址空间由于驱动和应用处于同一地址空间应用使用ioctl通过指针传递给驱动的数据实际上是指向同一片物理内存的所以在驱动中是可以访问这一块数据并正确处理的微内核中驱动程序是属于应用程序之外的某个进程比如网卡驱动是属于iopkt进程ioctl可以认为是一种封装的IPC机制所以驱动和应用工作在不同的地址空间这种情况下应用如果使用ioctl通过指针传递数据给驱动驱动是无法获取到正确的数据的。两者区别如下图所示因为这种区别QNX中ioctl一般只用来做一些不带参数的配置项避免数据错误传输的问题针对需要传输数据的配置项QNX中要使用devctl来代替比如我的示例strncpy(ifcmd-ifd_name, ifname, IFNAMSIZ);ifcmd-ifd_cmd PTP_ENABLE;ifcmd-ifd_data 1;ifcmd-ifd_len 4;//ioctl(sock_fd, SIOCSDRVSPEC, cmd);devctl(sock_fd, SIOCGDRVSPEC, drv_data, sizeof(ifcmd) sizeof(drv_data), NULL);使用devctl时数据会直接打包进IPC的message里面通过message一起发给目标进程从而保证目标进程在使用数据时是与发送进程一致的数据。以上信息参考了下面的文章感兴趣的朋友可以直接去看一下原文QNX network driver custom ioctls - Pebble Bay