ICMP_ECHO消息类型用于测试远程主机是否可连接。当主机接收到ICMP_ECHO消息时,会以ICMP_ECHOREPLY消息回复。
上图中,当主机X传输IP封包到主机Y时,会发生下列事情:
1.主机X传送一个要给主机Y的封包到路由器RT1。
2.路由器RT1会查询它的路由表,发现下一个跳点是路由器RT2.路由器RT1也了解到因为路由器RT2和主机X位于相同子网上,所以主机X可以直接把封包传给路由器RT2.
3.路由器RT1传送一条ICMP_REDIRECT消息给主机X,通知主机X有更好的路径。主机X就会存储该路径,在下次采用。
4.路由器RT1把封包转发至路由器RT2.
ICMP_TIMESTAMP消息类型可用于要求远程主机提供一个时间戳(实际上是两个),然后利用此时间戳使那些主机的时钟同步。接收ICMP_TIMESTAMP消息的主机会用ICMP_TIMESTAMPREPLY消息回复。
这些ICMP类型用的不多,实现相同的目的采用其他协议更合适(如NTP)。
ICMP消息可由内核以及用户空间程序传输。用户空间应用程序会使用raw IP套接字界面(如traceroute和ping,都是使用ICMP协议)。其他使用raw IP套接字接口来进行传输或监听ICMP消息的是各种路由协议。
229 #define XRLIM_BURST_FACTOR 6
230 int xrlim_allow(struct dst_entry *dst, int timeout)
231 {
232 unsigned long now;
233
234 now = jiffies;
235 dst->rate_tokens += now - dst->rate_last;
236 dst->rate_last = now;
237 if (dst->rate_tokens > XRLIM_BURST_FACTOR*timeout)
238 dst->rate_tokens = XRLIM_BURST_FACTOR*timeout;
239 if (dst->rate_tokens >= timeout) {
240 dst->rate_tokens -= timeout;
241 return 1;
242 }
243 return 0;
244 }
xrlim_allow会施加简单的令牌桶算法。每当它被调用时,就会更新可用的dst->rate_tokens令牌(以jiffies为单位测量),来确保累计的令牌不会多过预定的最大值(XRLIM_BURST_FACTOR ),而且如果可用令牌足够的话,就可让ICMP消息传输。输入参数timeout代表的是要施加的速率,以HZ为单位表示。例如,1*HZ指的速率限制是每秒一条ICMP消息。
769 /*
770 * Handle ICMP_ECHO ("ping") requests.
771 *
772 * RFC 1122: 3.2.2.6 MUST have an echo server that answers ICMP echo
773 * requests.
774 * RFC 1122: 3.2.2.6 Data received in the ICMP_ECHO request MUST be
775 * included in the reply.
776 * RFC 1812: 4.3.3.6 SHOULD have a config option for silently ignoring
777 * echo requests, MUST have default=NOT.
778 * See also WRT handling of options once they are done and working.
779 */
780
781 static void icmp_echo(struct sk_buff *skb)
782 {
783 struct net *net;
784
785 net = dev_net(skb_dst(skb)->dev);
786 if (!net->ipv4.sysctl_icmp_echo_ignore_all) {
787 struct icmp_bxm icmp_param;
788
789 icmp_param.data.icmph = *icmp_hdr(skb);
790 icmp_param.data.icmph.type = ICMP_ECHOREPLY;
791 icmp_param.skb = skb;
792 icmp_param.offset = 0;
793 icmp_param.data_len = skb->len;
794 icmp_param.head_len = sizeof(struct icmphdr);
795 icmp_reply(&icmp_param, skb);
796 }
797 }
icmp_unreach函数:
内核按每个CPU存储统计资料,此外,就每个CPU而言,内核也会区分在软件中断环境内外所更新的统计资料。