2. IPIP協議
Linux
2.6定義
了一種新的協議類型
--即本章講解的IPIP
(
IPPROTO_IPIP
)
,其主要實現主要基於兩個檔案
new_tunnel.c
和
ipip.c。現在開始分析源碼。
IPIP
模組載入與卸載。
static int __init ipip_init(void)<br />{<br />int err;<br />printk(banner);<br />if (xfrm4_tunnel_register(&ipip_handler, AF_INET)) {<br />printk(KERN_INFO "ipip init: can't register tunnel/n");<br />return -EAGAIN;<br />}<br />err = register_pernet_gen_device(&ipip_net_id, &ipip_net_ops);<br />if (err)<br />xfrm4_tunnel_deregister(&ipip_handler, AF_INET);<br />return err;<br />}<br />
首先是將ipip協議使用
xfrm4_tunnel_register
按照ip協議類型和優先順序加入到ip隧道中,然後在函數內部調用register_pernet_gen_device()函數來初始化全域的init_net網路空間結構。
可以看到他向register_pernet_gen_device傳遞了二個參數結構ipip_net_id和ipip_net_ops
static struct pernet_operations ipip_net_ops = {<br />.init = ipip_init_net,<br />.exit = ipip_exit_net,<br />};
我們再看看register_pernet_gen_device是如何?的。
int register_pernet_gen_device(int *id, struct pernet_operations *ops)<br />{<br />int error;<br />mutex_lock(&net_mutex);<br />again:<br />error = ida_get_new_above(&net_generic_ids, 1, id);<br />if (error) {<br />if (error == -EAGAIN) {<br />ida_pre_get(&net_generic_ids, GFP_KERNEL);<br />goto again;<br />}<br />goto out;<br />}<br />error = register_pernet_operations(&pernet_list, ops);<br />if (error)<br />ida_remove(&net_generic_ids, *id);<br />else if (first_device == &pernet_list)<br />first_device = &ops->list;<br />out:<br />mutex_unlock(&net_mutex);<br />return error;<br />
首先判斷ipip_net_ops的init鉤子是否鏈入了,我們看到上面他的結構中是ipip_init_net函數,那麼就要進一步調用這個函數初始化我們這裡的init_net網路命名空間。
static int ipip_init_net(struct net *net)<br />{<br />int err;<br />struct ipip_net *ipn;<br />err = -ENOMEM;<br />ipn = kzalloc(sizeof(struct ipip_net), GFP_KERNEL);<br />if (ipn == NULL)<br />goto err_alloc;<br />err = net_assign_generic(net, ipip_net_id, ipn);<br />if (err < 0)<br />goto err_assign;<br />ipn->tunnels[0] = ipn->tunnels_wc;<br />ipn->tunnels[1] = ipn->tunnels_l;<br />ipn->tunnels[2] = ipn->tunnels_r;<br />ipn->tunnels[3] = ipn->tunnels_r_l;<br />ipn->fb_tunnel_dev = alloc_netdev(sizeof(struct ip_tunnel),<br /> "tunl0",<br /> ipip_tunnel_setup);<br />if (!ipn->fb_tunnel_dev) {<br />err = -ENOMEM;<br />goto err_alloc_dev;<br />}<br />dev_net_set(ipn->fb_tunnel_dev, net);<br />ipip_fb_tunnel_init(ipn->fb_tunnel_dev);<br />if ((err = register_netdev(ipn->fb_tunnel_dev)))<br />goto err_reg_dev;<br />return 0;<br />err_reg_dev:<br />free_netdev(ipn->fb_tunnel_dev);<br />err_alloc_dev:<br />/* nothing */<br />err_assign:<br />kfree(ipn);<br />err_alloc:<br />return err;<br />}
初始化網路裝置參數,並註冊網路裝置,至此,初始化過程完畢。
卸載網路裝置恰恰即上述過程的逆過程。
static void ipip_exit_net(struct net *net)<br />{<br />struct ipip_net *ipn;<br />ipn = net_generic(net, ipip_net_id);<br />rtnl_lock();<br />ipip_destroy_tunnels(ipn);<br />unregister_netdevice(ipn->fb_tunnel_dev);<br />rtnl_unlock();<br />kfree(ipn);<br />}