前言:IPIP隧道是一種三層隧道,通過把原來的IP包封裝在新的IP包里面,來創(chuàng)建隧道傳輸。本篇簡單分析Linux(2.6.32版本)中的IPIP隧道的實現(xiàn)過程,期望有所借鑒,造出輪子:-)
Linux中的IPIP隧道文件主要分布在tunnel4.c和ipip.c文件中。因為是三層隧道,在IP報文中填充的三層協(xié)議自然就不能是常見的TCP和UDP,所以,Linux抽象了一個隧道層,位置就相當(dāng)于傳輸層,主要的實現(xiàn)就是在tunnel4.c中。來看看他們的初始化:
抽象的隧道層和IPIP模塊都是以注冊模塊的方式進行初始化
module_init(tunnel4_init);module_init(ipip_init);首先看隧道層的初始化,主要的工作就是注冊隧道協(xié)議和對應(yīng)的處理函數(shù):
static int __init tunnel4_init(void){ if (inet_add_protocol(&tunnel4_protocol, IPPROTO_IPIP)) { printk(KERN_ERR "tunnel4 init: can't add protocol/n"); return -EAGAIN; }#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) if (inet_add_protocol(&tunnel64_protocol, IPPROTO_IPV6)) { printk(KERN_ERR "tunnel64 init: can't add protocol/n"); inet_del_protocol(&tunnel4_protocol, IPPROTO_IPIP); return -EAGAIN; }#endif return 0;}inet_add_protocol(&tunnel4_protocol, IPPROTO_IPIP)把IPIP隧道協(xié)議注冊進inet_protos全局數(shù)組中,而inet_protos中的其他協(xié)議注冊是在inet_init()中:
if (inet_add_protocol(&icmp_protocol, IPPROTO_ICMP) < 0) printk(KERN_CRIT "inet_init: Cannot add ICMP protocol/n"); if (inet_add_protocol(&udp_protocol, IPPROTO_UDP) < 0) printk(KERN_CRIT "inet_init: Cannot add UDP protocol/n"); if (inet_add_protocol(&tcp_protocol, IPPROTO_TCP) < 0) printk(KERN_CRIT "inet_init: Cannot add TCP protocol/n");#ifdef CONFIG_IP_MULTICAST if (inet_add_protocol(&igmp_protocol, IPPROTO_IGMP) < 0) printk(KERN_CRIT "inet_init: Cannot add IGMP protocol/n");#endif看一下隧道層的處理函數(shù):
static const struct net_protocol tunnel4_protocol = { .handler = tunnel4_rcv, .err_handler = tunnel4_err, .no_policy = 1, .netns_ok = 1,};這樣注冊完后,當(dāng)接收到三層類型是IPPROTO_IPIP時,就會調(diào)用tunnel4_rcv進行下一步的處理??梢哉f在隧道層對隧道協(xié)議進行的注冊,保證能夠識別接收到隧道包。而對隧道包的處理則是在IPIP中完成的。
for (handler = tunnel4_handlers; handler; handler = handler->next) if (!handler->handler(skb)) return 0;icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);在隧道層的處理函數(shù)中進一步調(diào)用注冊的不同隧道協(xié)議的處理函數(shù),分別處理。
新聞熱點
疑難解答
圖片精選