积累系统性知识
积聚技术精华
  首页    个人中心    撰写积文    建立课题    订立目标    整理积文    管理课题    管理目标    技能Get    代码积累 
Linux内核VPN实现源码分析(二)
error997 (error997)    2014-11-20 20:14:34      目标    课题
   2.  IPIP协议
   Linux 2.6定义 了一种新的协议类型 --即本章讲解的IPIP ( IPPROTO_IPIP ) ,其主要实现主要基于两个文件 new_tunnel.c 和 ipip.c。现在开始分析源码。
   
   
   IPIP 模块加载与卸载。

切换到: 纯代码  
   
static int __init ipip_init(void)  
{  
    int err;  
    printk(banner);  
    if (xfrm4_tunnel_register(&ipip_handler, AF_INET)) {  
        printk(KERN_INFO "ipip init: can't register tunnel/n");  
        return -EAGAIN;  
    }  
    err = register_pernet_gen_device(&ipip_net_id, &ipip_net_ops);  
    if (err)  
        xfrm4_tunnel_deregister(&ipip_handler, AF_INET);  
    return err;  
}


   首先是将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 = {  
    .init = ipip_init_net,  
    .exit = ipip_exit_net,  
};


   我们再看看register_pernet_gen_device是如何实现的。

切换到: 纯代码  
   
int register_pernet_gen_device(int *id, struct pernet_operations *ops)  
{  
    int error;  
    mutex_lock(&net_mutex);  
again:  
    error = ida_get_new_above(&net_generic_ids, 1, id);  
    if (error) {  
        if (error == -EAGAIN) {  
            ida_pre_get(&net_generic_ids, GFP_KERNEL);  
            goto again;  
        }  
        goto out;  
    }  
    error = register_pernet_operations(&pernet_list, ops);  
    if (error)  
        ida_remove(&net_generic_ids, *id);  
    else if (first_device == &pernet_list)  
        first_device = &ops->list;  
out:  
    mutex_unlock(&net_mutex);  
    return error;


   首先判断ipip_net_ops的init钩子是否链入了,我们看到上面他的结构中是ipip_init_net函数,那么就要进一步调用这个函数初始化我们这里的init_net网络命名空间。

切换到: 纯代码  
   
static int ipip_init_net(struct net *net)  
{  
    int err;  
    struct ipip_net *ipn;  
    err = -ENOMEM;  
    ipn = kzalloc(sizeof(struct ipip_net), GFP_KERNEL);  
    if (ipn == NULL)  
        goto err_alloc;  
    err = net_assign_generic(net, ipip_net_id, ipn);  
    if (err < 0)  
        goto err_assign;  
    ipn->tunnels[0] = ipn->tunnels_wc;  
    ipn->tunnels[1] = ipn->tunnels_l;  
    ipn->tunnels[2] = ipn->tunnels_r;  
    ipn->tunnels[3] = ipn->tunnels_r_l;  
    ipn->fb_tunnel_dev = alloc_netdev(sizeof(struct ip_tunnel),  
                       "tunl0",  
                       ipip_tunnel_setup);  
    if (!ipn->fb_tunnel_dev) {  
        err = -ENOMEM;  
        goto err_alloc_dev;  
    }  
    dev_net_set(ipn->fb_tunnel_dev, net);  
    ipip_fb_tunnel_init(ipn->fb_tunnel_dev);  
    if ((err = register_netdev(ipn->fb_tunnel_dev)))  
        goto err_reg_dev;  
    return 0;  
err_reg_dev:  
    free_netdev(ipn->fb_tunnel_dev);  
err_alloc_dev:  
    /* nothing */  
err_assign:  
    kfree(ipn);  
err_alloc:  
    return err;  
}


   初始化网络设备参数,并注册网络设备,至此,初始化过程完毕。
   卸载网络设备恰恰即上述过程的逆过程。

切换到: 纯代码  
   
static void ipip_exit_net(struct net *net)  
{  
    struct ipip_net *ipn;  
    ipn = net_generic(net, ipip_net_id);  
    rtnl_lock();  
    ipip_destroy_tunnels(ipn);  
    unregister_netdevice(ipn->fb_tunnel_dev);  
    rtnl_unlock();  
    kfree(ipn);  
}




转自 http://blog.csdn.net/y___y/article/details/5649291
(+0)技能Get

建议楼主:搜索关键字 |参考其他资源 |回复 |追问
  error997(error997):   个人中心    课题    目标    代码积累