<返回更多

一文读懂Linux网络命名空间

2022-03-22    linux上的码农
加入收藏

1.1 linux网络

1.2 网络实现的分层模型

 

一文读懂Linux网络命名空间

内核对这个分层模型的实现

 

 

 

一文读懂Linux网络命名空间

各层的数据都由首部和数据两部分组成

一文读懂Linux网络命名空间

在以太网帧中通过TCP/IP传输HTTP数据

 

更多linux内核视频教程文档资料免费领取后台私信【内核】自行获取.

一文读懂Linux网络命名空间

 

Linux内核源码/内存调优/文件系统/进程管理/设备驱动/网络协议栈-学习视频教程-腾讯课堂

 

2、网络命名空间net

2.1 网络命令空间net

struct net {
    atomic_t        passive;    /* To decided when the network
                                 * namespace should be freed.
                                 */
    atomic_t        count;      /* To decided when the network
                                 *  namespace should be shut down.
                                 */
    spinlock_t      rules_mod_lock;
    atomic64_t      cookie_gen;

    struct list_head        list;         /* list of network namespaces */
    struct list_head        cleanup_list; /* namespaces on death row */
    struct list_head        exit_list;    /* Use only net_mutex */
    struct user_namespace   *user_ns;     /* Owning user namespace */
    spinlock_t               nsid_lock;
    struct idr               netns_ids;

    struct ns_common         ns;

    struct proc_dir_entry   *proc_net;
    struct proc_dir_entry   *proc_net_stat;

#ifdef CONFIG_SYSCTL
    struct ctl_table_set    sysctls;
#endif

    struct sock             *rtnl;          /* rtnetlink socket */
    struct sock             *genl_sock;

    struct list_head         dev_base_head;
    struct hlist_head       *dev_name_head;
    struct hlist_head       *dev_index_head;
    unsigned int             dev_base_seq; /* protected by rtnl_mutex */
    int                      ifindex;
    unsigned int             dev_unreg_count;

    /* core fib_rules */
    struct list_head         rules_ops;


    struct net_device       *loopback_dev;      /* The loopback */
    struct netns_core       core;
    struct netns_mib        mib;
    struct netns_packet     packet;
    struct netns_unix       unx;
    struct netns_ipv4       ipv4;
#if IS_ENABLED(CONFIG_IPV6)
    struct netns_ipv6       ipv6;
#endif
#if IS_ENABLED(CONFIG_IEEE802154_6LOWPAN)
    struct netns_ieee802154_lowpan  ieee802154_lowpan;
#endif
#if defined(CONFIG_IP_SCTP) || defined(CONFIG_IP_SCTP_MODULE)
    struct netns_sctp       sctp;
#endif
#if defined(CONFIG_IP_DCCP) || defined(CONFIG_IP_DCCP_MODULE)
    struct netns_dccp       dccp;
#endif
#ifdef CONFIG_NETFILTER
    struct netns_nf     nf;
    struct netns_xt     xt;
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
    struct netns_ct     ct;
#endif
#if defined(CONFIG_NF_TABLES) || defined(CONFIG_NF_TABLES_MODULE)
    struct netns_NFTables   nft;
#endif
#if IS_ENABLED(CONFIG_NF_DEFRAG_IPV6)
    struct netns_nf_frag    nf_frag;
#endif
    struct sock         *nfnl;
    struct sock         *nfnl_stash;
#if IS_ENABLED(CONFIG_NETFILTER_NETLINK_ACCT)
    struct list_head    nfnl_acct_list;
#endif
#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
    struct list_head    nfct_timeout_list;
#endif
#endif
#ifdef CONFIG_WEXT_CORE
    struct sk_buff_head     wext_nlevents;
#endif
    struct net_generic __rcu    *gen;

    /* Note : following structs are cache line aligned */
#ifdef CONFIG_XFRM
    struct netns_xfrm       xfrm;
#endif
#if IS_ENABLED(CONFIG_IP_VS)
    struct netns_ipvs       *ipvs;
#endif
#if IS_ENABLED(CONFIG_MPLS)
    struct netns_mpls       mpls;
#endif
    struct sock            *diag_nlsk;
    atomic_t                fnhe_genid;
};

  1. count是一个标准的使用计数器,在使用特定的net实例前后,需要分别调用辅助函数get_net和put_net. 在count降低到0时,将释放该命名空间,并将其从系统中删除.
  2. 所有可用的命名空间都保存在一个双链表上,表头是net_namespace_list。list用作链表元素. copy_net_ns函数向该链表添加一个新的命名空间。在用create_new_namespace创建一组新的命名空间时,会自动调用该函数。
  3. 由于每个命名空间都包含不同的网络设备,这必然会反映到procfs的内容上(参见10.1节)。各命名空间的处理需要三个数据项:/proc/net由proc_net表示,而/proc/net/stats由proc_net_stats表示,proc_net_root指向当前命名空间的procfs实例的根结点,即/proc
  4. 每个命名空间都可以有一个不同的环回设备,而loopback_dev指向履行该职责的(虚拟)网络设备.
  5. 网络设备由struct net_device表示。与特定命名空间关联的所有设备都保存在一个双链表上,表头为dev_base_head。各个设备还通过另外两个双链表维护:一个将设备名用作散列键(dev_name_head),另一个将接口索引用作散列键(dev_index_head)。
struct net
{
 /*  ......  */
    struct net_device       *loopback_dev;      /* The loopback */
    struct netns_core       core;
    struct netns_mib        mib;
    struct netns_packet     packet;
    struct netns_unix       unx;
    struct netns_ipv4       ipv4;
#if IS_ENABLED(CONFIG_IPV6)
    struct netns_ipv6       ipv6;
#endif
 /*  ......  */
}

//  http://lxr.free-electrons.com/source/net/core/net_namespace.c?v=4.7#L35
struct net init_net = {
    .dev_base_head = LIST_HEAD_INIT(init_net.dev_base_head),
};
EXPORT_SYMBOL(init_net);

LIST_HEAD(net_namespace_list);
EXPORT_SYMBOL_GPL(net_namespace_list);

2.2 初始化 & 清理元组 pernet_operations(创建命名空间)

初始化 & 清理元组pernet_operations

//  http://lxr.free-electrons.com/source/include/net/net_namespace.h?v=4.7#L288
struct pernet_operations {
    struct list_head list;
    int (*init)(struct net *net);
    void (*exit)(struct net *net);
    void (*exit_batch)(struct list_head *net_exit_list);
    int *id;
    size_t size;
};

//  http://lxr.free-electrons.com/source/include/net/net_namespace.h?v=4.7#L316
int register_pernet_subsys(struct pernet_operations *);
void unregister_pernet_subsys(struct pernet_operations *);
int register_pernet_device(struct pernet_operations *);
void unregister_pernet_device(struct pernet_operations *);

一文读懂Linux网络命名空间

 

 

static LIST_HEAD(pernet_list);
static struct list_head *first_device = &pernet_list;
DEFINE_MUTEX(net_mutex);

网络命令空间的创建

//   http://lxr.free-electrons.com/source/net/core/net_namespace.c?v=2.6.32#L120

//  这个函数用于向内核中添加一个网络命名空间
// struct net *net_create(void);
// 这个函数主要做了三件事 :
// 1.  通过struct net*net_alloc(void)函数分配了一个structnet结构体
// 2.  通过setup_net(struct net*ns)函数对分配的struct net结构体进行了相应的设置;
// 3.  将分配的struct net结构体加入到 net_namespace_list的双链表尾部

//  http://lxr.free-electrons.com/source/net/core/net_namespace.c?v=2.6.32#L143
struct net *copy_net_ns(unsigned long flags, struct net *old_net)
{
    if (!(flags & CLONE_NEWNET))
        return get_net(old_net);
    return net_create();
}

// 1. 如果设置了CLONE_NEWNET, 就通过net_create创建一个新的net网络命令空间
// 2. 否则的话, 返回旧的网络命令空间

释放一个网络命名空间

static void net_free(struct net *net)
{
    kfree(rcu_access_pointer(net->gen));
    kmem_cache_free(net_cachep, net);
}

void net_drop_ns(void *p)
{
    struct net *ns = p;
    if (ns && atomic_dec_and_test(&ns->passive))
        net_free(ns);
}

2.3 总结

  1. 网络子系统实现的所有全局函数,都需要一个网络命名空间作为参数,而网络子系统的所有全局属性,只能通过所述命名空间迂回访问.
  2. linux系统包括默认的命名空间 : init_net和用户自定义的net namespace一般是默认的命名空间:init_net, 也就是所有的"网络通信协议"+"网络设备"都是属于默认的命名空间.
  3. 网络命名空间定义了2个链表, pernet_list和net_namespace_list init_net会被链接到net_namespace_list这个双向链表上 pernet_operations结构将被链接到first_device = pernet_list这个双向链表上
  4. 如果没自定义网络命名空间的话,所有想用网络命名空间时都将利用默认的init_net

3、网络命令空间设备

命名空间设备指的是那些?

3.1 虚拟网络设备

一文读懂Linux网络命名空间

 

 

3.2 物理网络设备

3.3 namespace与socket, 网络设备的关系

声明:本站部分内容来自互联网,如有版权侵犯或其他问题请与我们联系,我们将立即删除或处理。
▍相关推荐
更多资讯 >>>