在procfs一節中我們提到過ioctl,它的作用編寫過驅動和從事過網絡程式設計的人,一定不會陌生. 就是由于它架構的思路的精妙之處,屏蔽了大量抽象的東西.這裡我們就分析下它的使用和架構,當然這裡不會分析ioctl系統調用的實作.這裡參考資料有《linux裝置驅動程式》,《深入了解linux網絡技術内幕》 ,當然也少不了網上好的文章和文章.
或許我們最熟悉就是檔案的操作,檔案有read、write當然還有其他一些的操作,這裡的工作就給了ioctl. 這裡我們首先說一下驅動程式裡關于ioctl函數的使用.
這裡舉一個網絡裝置的例子: 比如我們建立一個gre接口,在核心裡(核心版本3.1.1)net/ipv4/ip_gre.c中 我們看它的核心啟動必須初始化的部分:
module_init(ipgre_init);
我們展開 ipgre_init函數:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | |
這裡我們隻關心 register_pernet_device(&ipgre_net_ops); 故名思意它會注冊一個網絡裝置
我們看看ipgre_net_ops的初始化
1 2 3 4 5 6 | |
這裡我們看核心必須初始化的部分 .init = ipgre_init_net :
1 2 3 4 5 6 7 8 9 10 11 12 | |
這裡建立gre0接口,并用 ipgre_tunnel_setup來完成部分初始化工作.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | |
這裡ipgre_netdev_ops 即完成了裝置相關的操作函數的初始化(如果使用者空間調用就會調用相應的函數)
1 2 3 4 5 6 7 8 9 10 11 12 | |
我們看到了關于裝置ioctl的初始化.對沒錯. 這裡核心已經很好的把底層具體的ioctl操作和gre0裝置關聯了起來.
下面就看看使用者空間如何調用:
這裡簡單的說明下:
int fd;
struct ifreq ifr;
fd= open("/dev/gre0");
if(fd < 0 ) return -1;
...
if( ioctl(fd,SIOCGETTUNNEL,&ifr))
.....
當然使用者空間也要有SIOCGETTUNNEL的定義 ,核心空間的是在include/linux/if_tunnel.h中定義.這裡所說是驅動裡私有的ioctl的使用.
#define SIOCGETTUNNEL (SIOCDEVPRIVATE + 0)
#define SIOCADDTUNNEL (SIOCDEVPRIVATE + 1)
#define SIOCDELTUNNEL (SIOCDEVPRIVATE + 2)
......
#define SIOCCHG6RD (SIOCDEVPRIVATE + 11)
在linux系統預設給dev預留了16個私有的ioctl,在include/linux/sockios.h中
1 2 3 4 5 6 7 8 9 10 11 12 | |
但是在實際情況中這個16個并不夠用,或者會産生混亂或者沖突,是以在驅動中還有另外一種定義和實作方法,也更為常用: 即通用驅動ioctl的實作方法:
IO(type,nr),_IOR(type,nr,datatype),_IOW(type,nr,datatype)。它們在<linux/ioctl.h>包含的<asm/ioctl.h>中有定義,是以在我們的驅動中應包含這個頭檔案。其中_IO()用做無參數的指令編号,_IOR()用做從驅動中讀取資料的指令編号,_IOW()用做寫入資料指令。 LDD中用:define SCULL_IOC_MAGIC 'k' ,define SCULL_IOCSQUANTUM _IOW(SCULL_IOC_MAGIC,1,int)表示SCULL_IOCSQUANTUM指令編号為向驅動中寫資料,指令編号為1,傳送參數類型為int.
下面就看一下簡單的使用方法:
#define MY_MAGIC 'k'
#define MY_GDEVNAME _IOR(MY_MAGIC, 1,int)
當然這個定義需要核心和使用者空間都有定義. 這裡不再詳述,具體請閱讀ldd3 第六章進階字元驅動程式操作一章.
這裡分析當然會有不到之處,僅作為好的學習的開始.
當然上面主要說明了驅動中ioctl的使用,也就不得不說下網絡程式設計中ioctl的使用,對于網絡程式設計中自定義這裡不再說明.
這裡僅就已經有的很多指令調用做一個簡單的總結.
具體的定義在include/linux/sockios.h中
ioctl 函數
本函數影響由fd 參數引用的一個打開的檔案。
#include<unistd.h> int ioctl( int fd, int request, ... );
傳回0 :成功
-1 :出錯
第三個參數總是一個指針,但指針的類型依賴于request 參數。
我們可以把和網絡相關的請求劃分為6 類:
套接口操作
檔案操作
接口操作
ARP
高速緩存操作
路由表操作
流系統
具體的使用和分類請參考《unix網絡程式設計》.下面貼出網絡ioctl調用流程圖:
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicGcq5SSykEN1IDN1cDO4UzMx8FOwIjN4cDMy8CXzIzLcFDMzEDMy8CX05WZth2YhRHdh9CX0VmbugXauVXYulGaj5yZvxmYvw1LcpDc0RHaiojIsJye.jpg)
這樣ioctl就統一了起來,驅動的ioctl和網絡的ioctl.其實實作思路都是一樣的,見開始gre0部分的實作.
來源:http://blog.chinaunix.net/uid-20786208-id-3479965.html