首页 > 代码库 > 《TCP/IP详解卷2:实现》笔记--选路插口

《TCP/IP详解卷2:实现》笔记--选路插口

一个进程使用选路域(routing domain)中的一个插口来发送和接收选路报文,socket系统调用需要制定一个PF_ROUTE

的族类型和一个SOCK_RAW的插口类型。该进程可以向内核发送以下五种选路报文:

1.RTM_ADD:增加一条新路由。

2.RTM_DELETE:删除一条已经存在的路由。

3.RTM_GET:取得有关一条路由的所有信息。

4.RTM_CHANGE:改变一条已经存在路由的网关、接口或者度量。

5.RTM_LOCK:说明内核不应该修改哪个变量。

本章简介选路域、为每个选路插口创建的选路控制块、处理进程产生的报文的函数(route_output)、发送选路报文给一个

或多个进程的函数(raw_input)、以及不同的支持一个选路插口上所有插口操作的函数。


1.routedomain和protosw结构

下图列出了称为routedomain的PF_ROUTE域的domain结构。


与支持多个协议(TCP、UDP和ICMP等)的Internet域不一样,在选路域中只支持SOCK_RAW类型的一种协议。下图列出

了PF_ROUTE域的协议转换项。



2.选路控制块

每当采用如下形式的调用创建一个选路插口时,

socket(PF_ROUTE,SOCK_RAW,protocol);

对协议的用户请求函数(route_usrreq)的一个对应的PRU_ATTACH请求分配一个选路控制块,并将它连接到插口结构上。

protocol参数可以将它发送给这个插口上的进程的报文类型限制为一个特定族。例如,如果将protocol参数说明为AF_INET,

只有包含了Internet地址的选路报文将被发送给这个进程。

我们把这些结构称为选路控制块,而不是原始控制块(raw control block),下图显示了rawcb结构的定义。


另外,分配了一个相同名字的全局结构,rawcb,作为这个双向链表的头,如下图所示。



3.route_output函数

当给协议的用户请求函数发送PRU_SEND请求时,就会调用route_output,这是一个进程向一个选路插口进行些操作所

引起的。函数的大概处理流程如下:



4.raw_input函数

向一个进程发送的所有选路报文----包括由内核产生的和由进程产生的----都被传递给raw_input,后者选择接收这个报文的

进程。该函数的大概处理流程如下:

1.比较地址族和协议。循环遍历每个选路控制块来查找一个匹配。

2.比较本地的和外部的地址。这两个测试比较了控制块里的本地地址和外部地址。

3.将报文添加到插口的接收缓存中。将报文的一个复制添加到那个插口的接收缓存中,并且在这个接收缓存等待的任何进程

都会被唤醒。


5.route_usrreq函数

route_usrreq是选路协议的用户请求函数。它被不同的操作调用。函数的大概处理流程如下:

1.如果是PRU_ATTACH:分配控制块

当进程调用socket时,就会发出PRU_ATTACH请求。为一个选路控制块分配内存。

2.如果是PRU_DETACH:计数器递减

close系统调用发出PRU_DETACH请求。如果socket结构指向一个协议控制块,route_cb结构的计数器中有两个被减1:一个

是any_count;另一个是基于该协议的计数器。

3.处理请求。函数raw_usrreq被调用来进一步处理PRU_xxx请求。

4.计数器递增。

5.连接插口。永久地连接到新的插口来接收PF_ROUTE族的选路报文。

6.默认情况下使能SO_USELOOPBACK。使能SO_USELOOPBACK插口选项。这是一个默认使能的插口选项。


6.raw_usrreq函数

raw_usrreq完成在选路域中用户请求处理的大部分工作。它被route_usrreq函数所调用。用户请求的处理被划分成这两个函数,

是因为其他的一些协议调用raw_usrreq而不是route_userreq。raw_usrreq并不是想要成为pr_usrreq函数,相反,它是一个

被不同的pr_usrreq函数调用的公共的子例程。

函数的主要对各种PRU_XXX请求进行处理:

PRU_ATTACH请求时socket系统调用的一个结果,该请求会调用raw_attach函数将控制块连接到双向链表中。

PRU_DETACH是由close系统调用发出的请求。该请求会调用raw_detach函数从双向链表中删除这个控制块。

PRU_CONNECT2请求来自与socketpair系统调用,在路由选择域中不被支持。

PRU_DISCONNECT请求在PRU_DETACH请求之前由close发出,因为一个选路插口总是连接的。该请求会调用raw_disconnect释放该插口的控制块。

PRU_SHUTDOWN请求时shutdown系统调用发出的,该请求会调用socantsendmore函数禁止以后的写操作。

PRU_SEND请求时sosend发出的,最终会调用pr_output函数,也就是route_output函数。

如果发出了一个PRU_ABORT请求,该控制块被断开连接,插口被释放,然后断开连接。

PRU_SENSE请求时有fstat系统调用发出的,函数返回OK。

PRU_RCVOOB,PRU_RCVD,PRU_LISTEN,PRU_ACCEPT,PRU_SENDOOB请求不被支持。

PRU_SOCKADDR和PRU_PEERADDR请求分别来自与getsockname和getpeername系统调用。前者总是返回一个错误,

因为设置本地地址的bind系统调用在路由选路域中不被支持。后者总是返回插口地址结构route_src的内容,这个内容是由

route_usrreq作为外部地址设置的。



《TCP/IP详解卷2:实现》笔记--选路插口