Linux NameSpace

NameSpace 命名空间/名称空间

一、简介
1)Linux Namespace:是Linux提供的一种内核级别环境隔离的方法。
1)Linux Namespaces 机制提供了一种资源隔离方案。PID,IPC,Network等系统资源不再是全局性的,而是属于特定的Namespace。
每个Namespace里面的资源对其他Namespace都是透明的。要创建新的Namespace,只需要在调用clone时指定相应的flag。Linux
Namespaces机制为实现基于容器的虚拟化技术提供了很好的基础。
3)演示代码:test_clon.c

#define _GNU_SOURCE 
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <sched.h>
#include <signal.h>
#include <unistd.h>

/* 定义一个给 clone 用的栈,栈大小1M */
#define STACK_SIZE (1024 * 1024) 
static char container_stack[STACK_SIZE];

char* const container_args[] = {
    "/bin/bash",
    NULL
};

int container_main(void* arg)
{
    printf("Container - inside the container!\n");
    /* 直接执行一个shell,以便我们观察这个进程空间里的资源是否被隔离了 */
    execv(container_args[0], container_args);
    printf("Something's wrong!\n");
    return 1;
}

int main()
{
    printf("Parent - start a container!\n");
    /* 调用clone函数,其中传出一个函数,还有一个栈空间的(为什么传尾指针,因为栈是反着的) */
    int container_pid = clone(container_main, container_stack+STACK_SIZE, SIGCHLD, NULL);
    /* 等待子进程结束 */
    waitpid(container_pid, NULL, 0);
    printf("Parent - container stopped!\n");
    return 0;
}

/*
1.开辟一个新的命名空间

zhanglu@zhanglu0704:~/zhanglu0704/05_test/20180425$ gcc test_clon.c -o clon
zhanglu@zhanglu0704:~/zhanglu0704/05_test/20180425$ echo $$                  ## 显示进程号
14784

zhanglu@zhanglu0704:~/zhanglu0704/05_test/20180425$ ./clon
Parent - start a container!
Container - inside the container!
zhanglu@zhanglu0704:~/zhanglu0704/05_test/20180425$echo $$
14991                                                                        ## 进入新的命名空间,

zhanglu@zhanglu0704:~/zhanglu0704/05_test/20180425$ exit                     ## 退出这一空间
exit
Parent - container stopped!
zhanglu@zhanglu0704:~/zhanglu0704/05_test/20180425$echo $$
14784                                                                       ## 回到开始时的空间
*/

<1> 分类
当前,Linux 支持6种不同类型的命名空间:
1.Mount namespaces:提供磁盘挂载点和文件系统的隔离能力
2.UTS namespaces :提供主机名隔离能力
3.IPC namespaces :提供进程间通信的隔离能力
4.PID namespaces :提供进程隔离能力
5.Network namespaces :提供网络隔离能力
6.User namespaces:提供用户隔离能力

<2> 查看当前进程的namespace:

$ echo $$              ##查看当前进程号
$ ls -al /proc/$$/ns/           ##查看命名空间
dr-x--x--x 2 user user 0 四月 25 16:43 ./
dr-xr-xr-x 9 user user 0 四月 25 16:38 ../
lrwxrwxrwx 1 user user 0 四月 25 16:43 cgroup -> cgroup:[4026531835]      
lrwxrwxrwx 1 user user 0 四月 25 16:43 ipc -> ipc:[4026531839]              ##不同的Namespace都有不同的编号 
lrwxrwxrwx 1 user user 0 四月 25 16:43 mnt -> mnt:[4026531840]
lrwxrwxrwx 1 user user 0 四月 25 16:43 net -> net:[4026531957]
lrwxrwxrwx 1 user user 0 四月 25 16:43 pid -> pid:[4026531836]
lrwxrwxrwx 1 user user 0 四月 25 16:43 user -> user:[4026531837]
lrwxrwxrwx 1 user user 0 四月 25 16:43 uts -> uts:[4026531838]

<3> 挂载隔离的命名空间(CLONE_NEWNS)
1)当调用clone时,设定了CLONE_NEWNS,就会创建一个新的mount Namespace。每个进程都存在于一个mount Namespace
里面,mount Namespace为进程提供了一个文件层次视图。如果不设定这个flag,子进程和父进程将共享一个mount
Namespace,其后子进程调用mount或umount将会影响到所有该Namespace内的进程。
2)如果子进程在一个独立的mount Namespace里面,就可以调用mount或umount建立一份新的文件层次视图。该flag配合
pivot_root系统调用,可以为进程创建一个独立的目录空间。
a.不进行隔离的mount
使用tmpfs这种基于内存的文件系统来模拟

$ echo $$
15541
$ mkdir /tmp/test/
$ sudo mount -t tmpfs tmpfs /tmp/test
$ cd /tmp/test/
$ touch aaa bbb ccc
另起终端查看
$ echo $$
16503
$ ls /tmp/test/
aaa  bbb  ccc
$ sudo umount /tmp/test/
b.隔离的挂载
# echo $$
17391
# unshare --mount /bin/bash
# echo $$
17467                                              ## 已经进入另一进程了
# ps -ef |grep 17391 |grep -v grep
root     17391 17390  0 17:09 pts/28   00:00:00 -su
root     17467 17391  0 17:09 pts/28   00:00:00 /bin/bash         ## 新进程是原进程的子进程
# mount -t tmpfs tmpfs /tmp/test/
# cd /tmp/test/
# touch aaa bbb ccc
# ls
aaa  bbb  ccc
另起终端查看
$ echo $$
16503
$ ls /tmp/test/
空
$ sudo ls -al /proc/17391/ns/mnt
lrwxrwxrwx 1 root root 0 四月 25 17:17 /proc/17391/ns/mnt -> mnt:[4026531840]          ## mount 命名空间A
$ sudo ls -al /proc/17467/ns/mnt
lrwxrwxrwx 1 root root 0 四月 25 17:17 /proc/17467/ns/mnt -> mnt:[4026532541]          ## mount 命名空间B
$ sudo ls -al /proc/16503/ns/mnt 
lrwxrwxrwx 1 user user 0 四月 25 17:18 /proc/16503/ns/mnt -> mnt:[4026531840]    ## A

3)演示代码test_mount.c

#define _GNU_SOURCE 
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <sched.h>
#include <signal.h>
#include <unistd.h>

/* 定义一个给 clone 用的栈,栈大小1M */
#define STACK_SIZE (1024 * 1024) 
static char container_stack[STACK_SIZE];

char* const container_args[] = {
    "/bin/bash",
    NULL
};

int container_main(void* arg) 
{ 
    printf("Container [%5d] - inside the container!\n", getpid()); 
    sethostname("container",10); 
    /* 重新mount proc文件系统到 /proc下 */ 
    system("mount -t proc proc /proc"); 
    execv(container_args[0], container_args); 
    printf("Something's wrong!\n"); 
    return 1; 
} 

int main() 
{ 
    printf("Parent [%5d] - start a container!\n", getpid()); 
    /* 启用Mount Namespace - 增加CLONE_NEWNS参数 */ 
    int container_pid = clone(container_main, container_stack+STACK_SIZE,  
            CLONE_NEWUTS | CLONE_NEWIPC | CLONE_NEWPID | CLONE_NEWNS | SIGCHLD, NULL); 
    waitpid(container_pid, NULL, 0); 
    printf("Parent - container stopped!\n"); 
    return 0; 
}

/*
同理,加入了挂载点隔离,程序执行后,两个空间的挂载点互相隔离,
A、B空间同时对同一目标文件进行mount、umount互不影响。 

$ sudo ./mnt 
Parent [26424] - start a container!
Container [    1] - inside the container!
# ls /proc/
1       buddyinfo  consoles  diskstats    fb           iomem    kallsyms   kmsg         loadavg  misc     net           schedstat  softirqs  sysrq-trigger  timer_stats  version_signature
15      bus        cpuinfo   dma          filesystems  ioports  kcore      kpagecgroup  locks    modules  pagetypeinfo  scsi       stat      sysvipc        tty          vmallocinfo
acpi    cgroups    crypto    driver       fs           ipmi     keys       kpagecount   mdstat   mounts   partitions    self       swaps     thread-self    uptime       vmstat
asound  cmdline    devices   execdomains  interrupts   irq      key-users  kpageflags   meminfo  mtrr     sched_debug   slabinfo   sys       timer_list     version      zoneinfo
# ps -aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.0  24588  5692 pts/1    S    20:42   0:00 /bin/bash
root        16  0.0  0.0  39104  3360 pts/1    R+   20:43   0:00 ps -aux
# top
top - 20:44:23 up 2 days,  4:25,  1 user,  load average: 0.98, 1.01, 0.72


Tasks:   2 total,   1 running,   1 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.8 us,  0.3 sy,  0.0 ni, 95.6 id,  3.3 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :  8091908 total,   211772 free,  3824828 used,  4055308 buff/cache
KiB Swap:  8303612 total,  8146764 free,   156848 used.  3380948 avail Mem 

PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND 
1 root      20   0   24588   5692   3648 S   0.0  0.1   0:00.01 bash                                                                                                                                    
17 root      20   0   43424   3740   3232 R   0.0  0.0   0:00.00 top                                                                                                                                     
 */

<4>主机名命名隔离的空间(系统调用CLONE_NEWUTS)
1)用于隔离不同命名空间(例如:容器内外)的主机名称和网络信息服务。
2)演示代码:test_utc.c

#define _GNU_SOURCE 
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <sched.h>
#include <signal.h>
#include <unistd.h>

/* 定义一个给 clone 用的栈,栈大小1M */
#define STACK_SIZE (1024 * 1024) 
static char container_stack[STACK_SIZE];

char* const container_args[] = {
    "/bin/bash",
    NULL
};


/* 与uts有关的代码:此处只演示主机名的隔离 */
int container_main(void* arg) 
{ 
    printf("Container - inside the container!\n"); 
    sethostname("container",10); /* 设置hostname */ 
    execv(container_args[0], container_args); 
    printf("Something's wrong!\n"); 
    return 1; 
} 

int main() 
{ 
    printf("Parent - start a container!\n"); 
    int container_pid = clone(container_main, container_stack+STACK_SIZE,  
            CLONE_NEWUTS | SIGCHLD, NULL); /*启用CLONE_NEWUTS Namespace隔离 */ 
    waitpid(container_pid, NULL, 0); 
    printf("Parent - container stopped!\n"); 
    return 0; 
}
/*
 $ gcc test_utc.c -o utc 
 $ echo $$
 21132
 $ hostname
 ubuntu-ssh01
 $ ./utc 
 Parent - start a container!
 Parent - container stopped!
 $ echo $$
 21132
 $ hostname
 ubuntu-ssh01
 $ 
 */

<5>IPC命名空间(系统调用CLONE_NEWIPC)
1)Inter-Process Communication (进程间通讯)方式主要包括管道、共享内存、信号量、消息队列、网络。
IPC具有一个全局的ID,Namespace需要对这个ID隔离,不能让别的Namespace的进程获取到。
2)原理上:
当调用clone时,设定了CLONE_NEWIPC,就会创建一个新的IPC Namespace,clone出来的进程将成为Namespace
里的第一个进程。一个IPC Namespace由一组System V IPC objects 标识符构成,这标识符由IPC相关的系统调
用创建。在一个IPC Namespace里面创建的IPC object对该Namespace内的所有进程可见,但是对其他Namespace
不可见,这样就使得不同Namespace之间的进程不能直接通信,就像是在不同的系统里一样。当一个IPC Namespace
被销毁,该Namespace内的所有IPC object会被内核自动销毁。
3)演示代码:test_ipc.c

#define _GNU_SOURCE 
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <sched.h>
#include <signal.h>
#include <unistd.h>

/* 定义一个给 clone 用的栈,栈大小1M */
#define STACK_SIZE (1024 * 1024) 
static char container_stack[STACK_SIZE];

char* const container_args[] = {
    "/bin/bash",
    NULL
};


/* 与uts有关的代码:此处只演示主机名的隔离 */
int container_main(void* arg) 
{ 
    printf("Container - inside the container!\n"); 
    sethostname("container",10); /* 设置hostname */ 
    execv(container_args[0], container_args); 
    printf("Something's wrong!\n"); 
    return 1; 
} 

int main() 
{ 
    printf("Parent - start a container!\n"); 
    int container_pid = clone(container_main, container_stack+STACK_SIZE,  
            CLONE_NEWUTS | CLONE_NEWIPC | SIGCHLD, NULL); /*新增CLONE_NEWIPC就可以了 */ 
    waitpid(container_pid, NULL, 0); 
    printf("Parent - container stopped!\n"); 
    return 0; 
}
/*
 $ echo $$                                                                 NameSpace A
 24399
 $ ipcs -q                                                                 查看消息队列-->没有
 --------- 消息队列 -----------
 键        msqid      拥有者  权限     已用字节数 消息      

 $ ipcmk -Q                                                                创建一个消息队列,
 消息队列 id:65536                                                          id是65536
 $ ipcs -q
 --------- 消息队列 -----------
 键        msqid      拥有者  权限     已用字节数 消息      
 0xf1fde496 65536      user    644        0            0           
=========================================================================
 $ sudo ./utc                                                              先执行UTC(隔离主机名)的命名空间代码
 [sudo] user 的密码: 
 Parent - start a container!
 Container - inside the container!
 # echo $$                                                                 NameSpace B
 24487
 # ipcs -q                                                                 消息队列65536仍然可见

 --------- 消息队列 -----------
 键        msqid      拥有者  权限     已用字节数 消息      
 0xf1fde496 65536      user    644        0            0           
 # exit                                                                    退出NameSpace B
 ===================================================================
 $ gcc test_ipc.c -o ipc
 $ sudo ./ipc 
 Parent - start a container!
 Container - inside the container!
 root@container # echo $$
 24835                                                                     NameSpace B
 # ipcs -q
 --------- 消息队列 -----------
 键        msqid      拥有者  权限     已用字节数 消息                         查不到消息队列65536,同样在该命名空间如果创建消息队列,对NameSpace A也不可见
 # exit
 exit
 Parent - container stopped!
 $ ipcrm -q 65536                                                          删除队列
 */

<6> PID 命名空间(系统调用CLONE_NEWPID)
1)空间内的PID是独立分配的,命名空间内的虚拟PID可能会与命名空间外的PID相冲突,于是命名空间内的PID映射到
命名空间外时会使用另外一个PID。例如,容器内init进程的第一个PID为1,而在命名空间外就是该PID已被系统的
init进程所使用,这时会使用另一个PID在系统中标识。
2)原理上:
1.当调用clone时,设定了CLONE_NEWPID,就会创建一个新的PID Namespace,clone出来的新进程将成为Namespace
里的第一个进程。一个PID Namespace为进程提供了一个独立的PID环境,PID Namespace内的PID将从1开始,在
Namespace内调用fork,vfork或clone都将产生一个在该Namespace内独立的PID。新创建的Namespace里的第一
个进程在该Namespace内的PID将为1,就像一个独立的系统里的init进程一样。该Namespace内的孤儿进程都将以
该进程为父进程,当该进程被结束时,该Namespace内所有的进程都会被结束。PID Namespace是层次性,新创建的
Namespace将会是创建它的进程属于的Namespace的子Namespace。
2.子Namespace中的进程对于父Namespace是可见的,一个进程将拥有不止一个PID,而是在所在的Namespace以及所有
直系祖先Namespace中都将有一个PID。
3.系统启动时,内核将创建一个默认的PID Namespace,该Namespace是所有以后创建的Namespace的祖先,因此系统所
有的进程在该Namespace都是可见的。
3)演示代码:test_pid.c

#define _GNU_SOURCE 
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <sched.h>
#include <signal.h>
#include <unistd.h>

/* 定义一个给 clone 用的栈,栈大小1M */
#define STACK_SIZE (1024 * 1024) 
static char container_stack[STACK_SIZE];

char* const container_args[] = {
    "/bin/bash",
    NULL
};


int container_main(void* arg) 
{ 
    printf("Container PID: [%5d] - inside the container!\n",getpid()); /* 此处的getpid()是为了获取容器的初始进程(init)的pid */
    sethostname("container",10); /* 设置hostname */ 
    execv(container_args[0], container_args); 
    printf("Something's wrong!\n"); 
    return 1; 
} 

int main() 
{ 
    printf("Parent PID:[%5d] - start a container!\n",getpid()); /* 此处的getpid()则是为了获取父进程的pid */ 
    int container_pid = clone(container_main, container_stack+STACK_SIZE,  
            CLONE_NEWUTS | CLONE_NEWIPC | CLONE_NEWPID | SIGCHLD, NULL); 
    /*新增CLONE_NEWPID即可,此处代表在UTS和IPC隔离的基础之上再进行PID的隔离,其实我们完全可以只加CLONE_NEWPID自己:这样的话就只代表隔离PID了 */ 
    waitpid(container_pid, NULL, 0); 
    printf("Parent - container stopped!\n"); 
    return 0; 
}

/*
 $ gcc test_pid.c -o pid
 $ echo $$                                                ## namespace A
 25638
 $ sudo ./pid 
 Parent PID:[25732] - start a container!                  ## 父进程 PID 是namespace A中的进程号
 Container PID: [    1] - inside the container!           ## PID隔离后 namespace B的 第一个进程PID id=1
 # echo $$
 1
 # exit
 exit
 Parent - container stopped!
 $ echo $$
 25638
 $  
 */

<7>网络命名空间(CLONE_NEWNET)
1)用于隔离网络资源(/proc/net、IP 地址、网卡、路由等)。后台进程可以运行在不同命名空间内的相同端口上,
用户还可以虚拟出一块网卡。每个网络命名空间都有自己的路由表,它自己的iptables设置提供nat和过滤。Linux
网络命名空间还提供了在网络命名空间内运行进程的功能。
2)原理上:
1.当调用clone时,设定了CLONE_NEWNET,就会创建一个新的Network Namespace。一个Network Namespace为进程提供了
一个完全独立的网络协议栈的视图。包括网络设备接口,IPv4和IPv6协议栈,IP路由表,防火墙规则,sockets等等。一
个Network Namespace提供了一份独立的网络环境,就跟一个独立的系统一样。
2.一个物理设备只能存在于一个Network Namespace中,可以从一个Namespace移动另一个Namespace中。
3.虚拟网络设备(virtual network device)提供了一种类似管道的抽象,可以在不同的Namespace之间建立隧道。利用虚拟化
网络设备,可以建立到其他Namespace中的物理设备的桥接。当一个Network Namespace被销毁时,物理设备会被自动移回
init NetworNamespace,即系统最开始的Namespace
3)内核源码实现:https://blog.csdn.net/hejin_some/article/details/71480862
4)连接网络命名空间的方法:
https://www.cnblogs.com/hustcat/p/3928261.html
https://blog.csdn.net/lineuman/article/details/52108191
a.使用一对veth pair :
使用一对虚拟ip对通讯模型
图片来源于网络

$ su -                        ## 需要root权限
/* 创建网络命名空间  */
# ip netns add ns1
# ip netns add ns2
# ip netns list
ns2
ns1
# ls /var/run/netns/
ns1 ns2
/* 
   创建veth pair(虚拟网卡对,只能成对创建)
   Virtual Ethernet Pair简称veth pair,是一个成对的端口。
   所有从这对端口一 端进入的数据包都将从另一端出来 
*/
# ip link add tap1 type veth peer name tap2
# ip link list
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: enp2s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
    link/ether 64:00:6a:19:6a:20 brd ff:ff:ff:ff:ff:ff
7: tap2@tap1: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 12:8b:1a:ca:a6:cd brd ff:ff:ff:ff:ff:ff
8: tap1@tap2: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 46:c5:09:8b:03:c8 brd ff:ff:ff:ff:ff:ff
/*将两个虚拟网卡分别添加到两个网络命名空间*/
# ip link set tap1 netns ns1
# ip link set tap2 netns ns2
# ip link list
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: enp2s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
    link/ether 64:00:6a:19:6a:20 brd ff:ff:ff:ff:ff:ff
/*在当前的网络命名空间中就没有这两个虚拟网卡了,两个虚拟网卡备份配到网络命名空间ns1,ns2中*/
# ip netns exec ns1 ip link list
7: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
8: tap1@if5: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 46:c5:09:8b:03:c8 brd ff:ff:ff:ff:ff:ff link-netnsid 1
/*通过ip netns exec可以配置namespace的网口*/
# ip netns exec ns2 ip link set dev lo up
# ip netns exec ns1 ifconfig tap1 172.4.101.101/24 up
# ip netns exec ns1 ifconfig
lo        Link encap:本地环回  
          inet 地址:127.0.0.1  掩码:255.0.0.0
          inet6 地址: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  跃点数:1
          接收数据包:8 错误:0 丢弃:0 过载:0 帧数:0
          发送数据包:8 错误:0 丢弃:0 过载:0 载波:0
          碰撞:0 发送队列长度:1 
          接收字节:672 (672.0 B)  发送字节:672 (672.0 B)

tap1      Link encap:以太网  硬件地址 8a:65:a9:53:3d:9f  
          inet 地址:172.4.101.101  广播:172.4.101.255  掩码:255.255.255.0
          UP BROADCAST MULTICAST  MTU:1500  跃点数:1
          接收数据包:0 错误:0 丢弃:0 过载:0 帧数:0
          发送数据包:0 错误:0 丢弃:0 过载:0 载波:0
          碰撞:0 发送队列长度:1000 
          接收字节:0 (0.0 B)  发送字节:0 (0.0 B)

/*按相同方式配置ns2的tap2为172.4.101.102*/
/* 然后可以试一下,ns1和ns2的通讯 */
# ip netns exec ns2 ping 172.4.101.101
# ip netns exec ns1 ping 172.4.101.102
而这两个ip对于其他NetWork NameSpace是不能访问的。

b.使用(网桥或openvswitch)和多对veth pair
two_veth_pair_brd.png
图片来源于网络

1.上述a方法使用一对虚拟ip实现两个命名空间的网络访问,但是对于两个以上(不包括两个)的NetWork NameSpace之间的通讯
就不能这么简单的实现了。(图one_veth_pair.png)
2.这时可以使用网桥和多对虚拟网卡的方式:每个网络命名空间和init网络空间都有一个虚拟网卡对进行通讯,而各个namespace
之间使用网桥或openvswitch交换机进行通讯(图:two_veth_pair_brd.png/two_veth_pair_switch.png)。

/*删掉刚才创建的虚拟网卡对*/
ip netns exec ns1 ip link set dev tap1 down
ip netns exec ns2 ip link set dev tap2 down
ip netns exec ns1 ip link del tap1 type veth peer name tap2
/* 创建ns3 */
# ip netns list
/*创建网桥*/
# apt install bridge-utils
BRIDGE=br-test
brctl addbr $BRIDGE
brctl stp   $BRIDGE off
ip link set dev $BRIDGE up
# ifconfig 
br-test   Link encap:以太网  硬件地址 7e:d1:0b:14:0e:e0  
          inet6 地址: fe80::7cd1:bff:fe14:ee0/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  跃点数:1
          接收数据包:0 错误:0 丢弃:0 过载:0 帧数:0
          发送数据包:30 错误:0 丢弃:0 过载:0 载波:0
          碰撞:0 发送队列长度:1000 
          接收字节:0 (0.0 B)  发送字节:4350 (4.3 KB)
# ip link list
15: br-test: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/ether 7e:d1:0b:14:0e:e0 brd ff:ff:ff:ff:ff:ff
/*
创建3对虚拟网卡,分别命名为tap1a,tap1b,tap2a,tap2b,tap3a,tap3b
并将 以a结尾的分别添加到对应的NameSpace,将以b结尾的添加到刚才创建的linux网桥br-test
*/
# ip link add tap1a type veth peer name tap1b
# ip link add tap2a type veth peer name tap2b
# ip link add tap3a type veth peer name tap3b
# ip link set tap1a netns ns1
# ip link set tap2a netns ns2
# ip link set tap3a netns ns3
# brctl addif br-test tap1b
# brctl addif br-test tap2b
# brctl addif br-test tap3b
/*配置3个namespace的网络*/
# ip netns exec ns1 ifconfig tap1a 172.4.101.101/24 up
# ip netns exec ns2 ifconfig tap2a 172.4.101.102/24 up
# ip netns exec ns3 ifconfig tap3a 172.4.101.103/24 up
/*set up 网桥中的虚拟网卡*/
# ip link set dev tap1b up
# ip link set dev tap2b up
# ip link set dev tap3b up
/*
  这时三个NameSpace之间可以互相通讯
  只要给网桥设置ip和子网掩码,即可在init网络命名空间访问ns1,ns2的ip。
*/

3.使用openvswitch 原理上和网桥一样,具体可以参考资料的。
two_veth_pair_switch.png

openvswitch_port.png
图片来源于网络

<8>User命名空间,
同进程 ID 一样,用户 ID 和组 ID 在命名空间内外是不一样的,并且在不同命名空间内可以存在相同的 ID。

二、NameSpace的具体实现:
https://blog.csdn.net/wangjianno2/article/details/50415835
https://blog.csdn.net/zhangyifei216/article/details/49788629
三、NameSpace的使用
https://blog.csdn.net/shichaog/article/details/41378145

参考:
https://www.cnblogs.com/linhaifeng/p/6657119.html
https://www.cnblogs.com/ilinuxer/p/6188450.html
https://lwn.net/Articles/531114/
NameSpace的具体实现:
https://blog.csdn.net/wangjianno2/article/details/50415835

猜你喜欢

转载自blog.csdn.net/frank_abagnale/article/details/80192571